envio 3.5.0-alpha.3 → 3.5.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 +17 -7
- package/src/BatchProcessing.res.mjs +8 -4
- 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 +35 -20
- package/src/ChainState.res.mjs +34 -11
- package/src/ChainState.resi +2 -0
- package/src/Config.res +41 -24
- package/src/Config.res.mjs +17 -14
- package/src/ContractRegisterContext.res +1 -1
- package/src/ContractRegisterContext.res.mjs +1 -1
- package/src/Core.res +1 -0
- package/src/CrossChainState.res +61 -16
- package/src/CrossChainState.res.mjs +37 -13
- package/src/CrossChainState.resi +3 -2
- 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 +261 -89
- package/src/FetchState.res.mjs +187 -63
- package/src/FinalizeBackfill.res +33 -6
- package/src/FinalizeBackfill.res.mjs +19 -1
- 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/IndexerLoop.res +9 -2
- package/src/IndexerLoop.res.mjs +8 -1
- package/src/IndexerState.res +41 -24
- package/src/IndexerState.res.mjs +36 -17
- package/src/IndexerState.resi +9 -7
- package/src/Internal.res +19 -17
- package/src/Internal.res.mjs +18 -9
- package/src/LoadLayer.res +1 -1
- package/src/LoadLayer.res.mjs +2 -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 +15 -7
- package/src/PgStorage.res +284 -258
- package/src/PgStorage.res.mjs +181 -208
- 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 +11 -14
- package/src/TestIndexer.res.mjs +14 -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/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 +50 -26
- package/src/db/InternalTable.res.mjs +32 -24
- package/src/db/Table.res +11 -1
- package/src/db/Table.res.mjs +9 -4
- 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/db/IndexRegistry.res +0 -219
- package/src/db/IndexRegistry.res.mjs +0 -195
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
let make = (
|
|
1
|
+
let make = (
|
|
2
|
+
~items: array<Internal.item>,
|
|
3
|
+
~endBlock: int,
|
|
4
|
+
~chainId: ChainId.t,
|
|
5
|
+
~addressStore: AddressStore.t,
|
|
6
|
+
): Source.t => {
|
|
2
7
|
let reportedHeight = max(endBlock, 1)
|
|
3
8
|
|
|
4
9
|
{
|
|
5
10
|
name: "SimulateSource",
|
|
6
|
-
simulateItems: items,
|
|
7
11
|
sourceFor: Sync,
|
|
8
|
-
|
|
12
|
+
chainId,
|
|
9
13
|
poweredByHyperSync: false,
|
|
10
14
|
pollingInterval: 0,
|
|
11
15
|
getBlockHashes: (~blockNumbers as _, ~logger as _) => {
|
|
@@ -27,8 +31,9 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
|
|
|
27
31
|
~logger as _,
|
|
28
32
|
) => {
|
|
29
33
|
// Mirror a real backend: return only the items this query would match —
|
|
30
|
-
// in the block range, part of the selection,
|
|
31
|
-
//
|
|
34
|
+
// in the block range, part of the selection, at or after the
|
|
35
|
+
// registration's own start block, and passing the same address gates a
|
|
36
|
+
// real source applies natively while routing (the emitter must be
|
|
32
37
|
// registered for the event's contract at or before the item's block, and
|
|
33
38
|
// any address-valued param filter must hold). Overlapping queries may
|
|
34
39
|
// return the same item more than once; the buffer dedups it.
|
|
@@ -36,27 +41,49 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
|
|
|
36
41
|
| Some(toBlock) => toBlock
|
|
37
42
|
| None => reportedHeight
|
|
38
43
|
}
|
|
39
|
-
|
|
44
|
+
// By registration index, not `eventConfig.id`: two registrations of the
|
|
45
|
+
// same event are independent and may sit in different partitions, so
|
|
46
|
+
// matching on the shared event id would let a sibling's items leak into
|
|
47
|
+
// this query.
|
|
48
|
+
let selectionRegistrationIndexes = Utils.Set.make()
|
|
40
49
|
selection.onEventRegistrations->Array.forEach(reg =>
|
|
41
|
-
|
|
50
|
+
selectionRegistrationIndexes->Utils.Set.add(reg.index)->ignore
|
|
42
51
|
)
|
|
43
52
|
|
|
53
|
+
// A client-filtered contract is queried address-free, so this partition
|
|
54
|
+
// holds none of its addresses and only the chain-wide store can answer
|
|
55
|
+
// for it — exactly the fallback every real source's router makes.
|
|
56
|
+
let isAddressAllowed = (address, ~contractName, ~blockNumber) =>
|
|
57
|
+
switch selection.clientFilteredContracts {
|
|
58
|
+
| Some(contractNames) if contractNames->Array.includes(contractName) =>
|
|
59
|
+
addressStore->AddressStore.isIndexedAt(address, contractName, blockNumber)
|
|
60
|
+
| _ => addressSet->AddressSet.containsAt(address, contractName, blockNumber)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The registration's own start block, which the contract-wide address gate
|
|
64
|
+
// can't express. Every native router applies it while routing.
|
|
65
|
+
let hasStarted = (onEventRegistration: Internal.onEventRegistration, ~blockNumber) =>
|
|
66
|
+
switch onEventRegistration.startBlock {
|
|
67
|
+
| Some(startBlock) => blockNumber >= startBlock
|
|
68
|
+
| None => true
|
|
69
|
+
}
|
|
70
|
+
|
|
44
71
|
let parsedQueueItems = items->Array.filter(item => {
|
|
45
72
|
let eventItem = item->Internal.castUnsafeEventItem
|
|
46
73
|
let {blockNumber, onEventRegistration} = eventItem
|
|
47
74
|
if blockNumber < fromBlock || blockNumber > toBlockQueried {
|
|
48
75
|
false
|
|
49
|
-
} else if !(
|
|
76
|
+
} else if !(selectionRegistrationIndexes->Utils.Set.has(onEventRegistration.index)) {
|
|
77
|
+
false
|
|
78
|
+
} else if !(onEventRegistration->hasStarted(~blockNumber)) {
|
|
50
79
|
false
|
|
51
80
|
} else {
|
|
52
81
|
let contractName = onEventRegistration.eventConfig.contractName
|
|
53
82
|
let emitterAllowed =
|
|
54
83
|
onEventRegistration.isWildcard ||
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
blockNumber,
|
|
59
|
-
)
|
|
84
|
+
eventItem.payload
|
|
85
|
+
->Internal.getPayloadSrcAddress
|
|
86
|
+
->isAddressAllowed(~contractName, ~blockNumber)
|
|
60
87
|
emitterAllowed &&
|
|
61
88
|
switch onEventRegistration.addressFilterParamGroups {
|
|
62
89
|
| None
|
|
@@ -64,8 +91,8 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
|
|
|
64
91
|
| Some(groups) =>
|
|
65
92
|
let params = eventItem.payload->Internal.getPayloadAddressParams
|
|
66
93
|
groups->Array.some(group =>
|
|
67
|
-
group->Array.every(
|
|
68
|
-
|
|
94
|
+
group->Array.every(
|
|
95
|
+
name => params->Dict.getUnsafe(name)->isAddressAllowed(~contractName, ~blockNumber),
|
|
69
96
|
)
|
|
70
97
|
)
|
|
71
98
|
}
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
4
4
|
|
|
5
|
-
function make(items, endBlock,
|
|
5
|
+
function make(items, endBlock, chainId, addressStore) {
|
|
6
6
|
let reportedHeight = Primitive_int.max(endBlock, 1);
|
|
7
7
|
return {
|
|
8
8
|
name: "SimulateSource",
|
|
9
9
|
sourceFor: "Sync",
|
|
10
|
-
|
|
10
|
+
chainId: chainId,
|
|
11
11
|
poweredByHyperSync: false,
|
|
12
12
|
pollingInterval: 0,
|
|
13
13
|
getBlockHashes: (param, param$1) => Promise.resolve({
|
|
@@ -23,21 +23,40 @@ function make(items, endBlock, chain) {
|
|
|
23
23
|
}),
|
|
24
24
|
getItemsOrThrow: (fromBlock, toBlock, addressSet, param, param$1, selection, param$2, param$3, param$4) => {
|
|
25
25
|
let toBlockQueried = toBlock !== undefined ? toBlock : reportedHeight;
|
|
26
|
-
let
|
|
26
|
+
let selectionRegistrationIndexes = new Set();
|
|
27
27
|
selection.onEventRegistrations.forEach(reg => {
|
|
28
|
-
|
|
28
|
+
selectionRegistrationIndexes.add(reg.index);
|
|
29
29
|
});
|
|
30
|
+
let isAddressAllowed = (address, contractName, blockNumber) => {
|
|
31
|
+
let contractNames = selection.clientFilteredContracts;
|
|
32
|
+
if (contractNames !== undefined && contractNames.includes(contractName)) {
|
|
33
|
+
return addressStore.isIndexedAt(address, contractName, blockNumber);
|
|
34
|
+
} else {
|
|
35
|
+
return addressSet.containsAt(address, contractName, blockNumber);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
let hasStarted = (onEventRegistration, blockNumber) => {
|
|
39
|
+
let startBlock = onEventRegistration.startBlock;
|
|
40
|
+
if (startBlock !== undefined) {
|
|
41
|
+
return blockNumber >= startBlock;
|
|
42
|
+
} else {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
30
46
|
let parsedQueueItems = items.filter(item => {
|
|
31
47
|
let blockNumber = item.blockNumber;
|
|
32
48
|
if (blockNumber < fromBlock || blockNumber > toBlockQueried) {
|
|
33
49
|
return false;
|
|
34
50
|
}
|
|
35
51
|
let onEventRegistration = item.onEventRegistration;
|
|
36
|
-
if (!
|
|
52
|
+
if (!selectionRegistrationIndexes.has(onEventRegistration.index)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (!hasStarted(onEventRegistration, blockNumber)) {
|
|
37
56
|
return false;
|
|
38
57
|
}
|
|
39
58
|
let contractName = onEventRegistration.eventConfig.contractName;
|
|
40
|
-
let emitterAllowed = onEventRegistration.isWildcard ||
|
|
59
|
+
let emitterAllowed = onEventRegistration.isWildcard || isAddressAllowed(item.payload.srcAddress, contractName, blockNumber);
|
|
41
60
|
if (!emitterAllowed) {
|
|
42
61
|
return false;
|
|
43
62
|
}
|
|
@@ -49,7 +68,7 @@ function make(items, endBlock, chain) {
|
|
|
49
68
|
return true;
|
|
50
69
|
}
|
|
51
70
|
let params = item.payload.params;
|
|
52
|
-
return groups.some(group => group.every(name =>
|
|
71
|
+
return groups.some(group => group.every(name => isAddressAllowed(params[name], contractName, blockNumber)));
|
|
53
72
|
});
|
|
54
73
|
return Promise.resolve({
|
|
55
74
|
knownHeight: reportedHeight,
|
|
@@ -65,8 +84,7 @@ function make(items, endBlock, chain) {
|
|
|
65
84
|
},
|
|
66
85
|
requestStats: []
|
|
67
86
|
});
|
|
68
|
-
}
|
|
69
|
-
simulateItems: items
|
|
87
|
+
}
|
|
70
88
|
};
|
|
71
89
|
}
|
|
72
90
|
|
package/src/sources/Source.res
CHANGED
|
@@ -64,7 +64,7 @@ type sourceFor = Sync | Fallback | Realtime
|
|
|
64
64
|
type t = {
|
|
65
65
|
name: string,
|
|
66
66
|
sourceFor: sourceFor,
|
|
67
|
-
|
|
67
|
+
chainId: ChainId.t,
|
|
68
68
|
poweredByHyperSync: bool,
|
|
69
69
|
/* Frequency (in ms) used when polling for new events on this network. */
|
|
70
70
|
pollingInterval: int,
|
|
@@ -95,8 +95,4 @@ type t = {
|
|
|
95
95
|
// Invoked by SourceManager once a rollback target is known so the source can
|
|
96
96
|
// drop any state that may now point at an orphaned chain (e.g. RPC block cache).
|
|
97
97
|
onReorg?: (~rollbackTargetBlock: int) => unit,
|
|
98
|
-
// Present only on the simulate source: the items a test fed in. The chain
|
|
99
|
-
// tracks which of these never reach a handler so the run can report dead
|
|
100
|
-
// simulate inputs on completion.
|
|
101
|
-
simulateItems?: array<Internal.item>,
|
|
102
98
|
}
|
|
@@ -32,7 +32,7 @@ let recordRequestStats = (sourceState: sourceState, requestStats: array<Source.r
|
|
|
32
32
|
// inline into the /metrics response.
|
|
33
33
|
type requestStatSample = {
|
|
34
34
|
sourceName: string,
|
|
35
|
-
chainId:
|
|
35
|
+
chainId: ChainId.t,
|
|
36
36
|
method: string,
|
|
37
37
|
count: int,
|
|
38
38
|
seconds: float,
|
|
@@ -81,7 +81,7 @@ let getActiveSource = sourceManager => sourceManager.activeSource
|
|
|
81
81
|
let getRequestStatSamples = (sourceManager: t): array<requestStatSample> => {
|
|
82
82
|
let samples = []
|
|
83
83
|
sourceManager.sourcesState->Array.forEach(sourceState => {
|
|
84
|
-
let chainId = sourceState.source.
|
|
84
|
+
let chainId = sourceState.source.chainId
|
|
85
85
|
sourceState.requestStats->Utils.Dict.forEachWithKey((agg, method) => {
|
|
86
86
|
samples
|
|
87
87
|
->Array.push({
|
|
@@ -101,7 +101,7 @@ let getRequestStatSamples = (sourceManager: t): array<requestStatSample> => {
|
|
|
101
101
|
// observed height yet are skipped.
|
|
102
102
|
type sourceHeightSample = {
|
|
103
103
|
sourceName: string,
|
|
104
|
-
chainId:
|
|
104
|
+
chainId: ChainId.t,
|
|
105
105
|
height: int,
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -111,7 +111,7 @@ let getSourceHeightSamples = (sourceManager: t): array<sourceHeightSample> => {
|
|
|
111
111
|
if sourceState.knownHeight > 0 {
|
|
112
112
|
samples->Array.push({
|
|
113
113
|
sourceName: sourceState.source.name,
|
|
114
|
-
chainId: sourceState.source.
|
|
114
|
+
chainId: sourceState.source.chainId,
|
|
115
115
|
height: sourceState.knownHeight,
|
|
116
116
|
})
|
|
117
117
|
}
|
|
@@ -425,7 +425,7 @@ let getSourceNewHeight = async (
|
|
|
425
425
|
logger->Logging.childTrace({
|
|
426
426
|
"msg": "onHeight subscription stale, switching to polling fallback",
|
|
427
427
|
"source": source.name,
|
|
428
|
-
"chainId": source.
|
|
428
|
+
"chainId": source.chainId,
|
|
429
429
|
})
|
|
430
430
|
let h = ref(initialHeight)
|
|
431
431
|
while h.contents <= knownHeight && !(newHeight.contents > initialHeight) {
|
|
@@ -585,7 +585,7 @@ let waitForNewBlock = async (sourceManager: t, ~knownHeight, ~isRealtime, ~reduc
|
|
|
585
585
|
|
|
586
586
|
let logger = Logging.createChild(
|
|
587
587
|
~params={
|
|
588
|
-
"chainId": sourceManager.activeSource.
|
|
588
|
+
"chainId": sourceManager.activeSource.chainId,
|
|
589
589
|
"knownHeight": knownHeight,
|
|
590
590
|
},
|
|
591
591
|
)
|
|
@@ -725,7 +725,7 @@ let executeQuery = async (
|
|
|
725
725
|
| Some(s) =>
|
|
726
726
|
if s.source !== sourceManager.activeSource {
|
|
727
727
|
let logger = Logging.createChild(
|
|
728
|
-
~params={"chainId": sourceManager.activeSource.
|
|
728
|
+
~params={"chainId": sourceManager.activeSource.chainId},
|
|
729
729
|
)
|
|
730
730
|
logger->Logging.childInfo({
|
|
731
731
|
"msg": "Switching data-source",
|
|
@@ -737,7 +737,7 @@ let executeQuery = async (
|
|
|
737
737
|
s
|
|
738
738
|
| None =>
|
|
739
739
|
let logger = Logging.createChild(
|
|
740
|
-
~params={"chainId": sourceManager.activeSource.
|
|
740
|
+
~params={"chainId": sourceManager.activeSource.chainId},
|
|
741
741
|
)
|
|
742
742
|
%raw(`null`)->ErrorHandling.mkLogAndRaise(~logger, ~msg=noSourcesError)
|
|
743
743
|
}
|
|
@@ -748,7 +748,7 @@ let executeQuery = async (
|
|
|
748
748
|
|
|
749
749
|
let logger = Logging.createChild(
|
|
750
750
|
~params={
|
|
751
|
-
"chainId": source.
|
|
751
|
+
"chainId": source.chainId,
|
|
752
752
|
"logType": "Block Range Query",
|
|
753
753
|
"partitionId": query.partitionId,
|
|
754
754
|
"source": source.name,
|
|
@@ -766,7 +766,7 @@ let executeQuery = async (
|
|
|
766
766
|
~addressSet=query.addresses,
|
|
767
767
|
~partitionId=query.partitionId,
|
|
768
768
|
~knownHeight,
|
|
769
|
-
~selection=query.selection,
|
|
769
|
+
~selection=query.selection->FetchState.narrowSelectionToRange(~toBlock),
|
|
770
770
|
~itemsTarget=query.itemsTarget,
|
|
771
771
|
~retry,
|
|
772
772
|
~logger,
|
|
@@ -896,7 +896,7 @@ let getBlockHashes = async (sourceManager: t, ~blockNumbers: array<int>, ~isReal
|
|
|
896
896
|
| Some(s) => s
|
|
897
897
|
| None =>
|
|
898
898
|
let logger = Logging.createChild(
|
|
899
|
-
~params={"chainId": sourceManager.activeSource.
|
|
899
|
+
~params={"chainId": sourceManager.activeSource.chainId},
|
|
900
900
|
)
|
|
901
901
|
%raw(`null`)->ErrorHandling.mkLogAndRaise(
|
|
902
902
|
~logger,
|
|
@@ -909,7 +909,7 @@ let getBlockHashes = async (sourceManager: t, ~blockNumbers: array<int>, ~isReal
|
|
|
909
909
|
|
|
910
910
|
let logger = Logging.createChild(
|
|
911
911
|
~params={
|
|
912
|
-
"chainId": source.
|
|
912
|
+
"chainId": source.chainId,
|
|
913
913
|
"logType": "Block Hash Query",
|
|
914
914
|
"source": source.name,
|
|
915
915
|
"retry": retry,
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as Utils from "../Utils.res.mjs";
|
|
4
4
|
import * as Source from "./Source.res.mjs";
|
|
5
5
|
import * as Logging from "../Logging.res.mjs";
|
|
6
|
+
import * as FetchState from "../FetchState.res.mjs";
|
|
6
7
|
import * as Performance from "../bindings/Performance.res.mjs";
|
|
7
8
|
import * as ErrorHandling from "../ErrorHandling.res.mjs";
|
|
8
9
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
@@ -36,7 +37,7 @@ function getActiveSource(sourceManager) {
|
|
|
36
37
|
function getRequestStatSamples(sourceManager) {
|
|
37
38
|
let samples = [];
|
|
38
39
|
sourceManager.sourcesState.forEach(sourceState => {
|
|
39
|
-
let chainId = sourceState.source.
|
|
40
|
+
let chainId = sourceState.source.chainId;
|
|
40
41
|
Utils.Dict.forEachWithKey(sourceState.requestStats, (agg, method) => {
|
|
41
42
|
samples.push({
|
|
42
43
|
sourceName: sourceState.source.name,
|
|
@@ -56,7 +57,7 @@ function getSourceHeightSamples(sourceManager) {
|
|
|
56
57
|
if (sourceState.knownHeight > 0) {
|
|
57
58
|
samples.push({
|
|
58
59
|
sourceName: sourceState.source.name,
|
|
59
|
-
chainId: sourceState.source.
|
|
60
|
+
chainId: sourceState.source.chainId,
|
|
60
61
|
height: sourceState.knownHeight
|
|
61
62
|
});
|
|
62
63
|
return;
|
|
@@ -350,7 +351,7 @@ async function getSourceNewHeight(sourceManager, sourceState, knownHeight, stall
|
|
|
350
351
|
Logging.childTrace(logger, {
|
|
351
352
|
msg: "onHeight subscription stale, switching to polling fallback",
|
|
352
353
|
source: source.name,
|
|
353
|
-
chainId: source.
|
|
354
|
+
chainId: source.chainId
|
|
354
355
|
});
|
|
355
356
|
let h = initialHeight;
|
|
356
357
|
while (h <= knownHeight && newHeight.contents <= initialHeight) {
|
|
@@ -506,7 +507,7 @@ function getNextSource(sourceManager, isRealtime, excludedSources) {
|
|
|
506
507
|
async function waitForNewBlock(sourceManager, knownHeight, isRealtime, reducedPolling) {
|
|
507
508
|
let sourcesState = sourceManager.sourcesState;
|
|
508
509
|
let logger = Logging.createChild({
|
|
509
|
-
chainId: sourceManager.activeSource.
|
|
510
|
+
chainId: sourceManager.activeSource.chainId,
|
|
510
511
|
knownHeight: knownHeight
|
|
511
512
|
});
|
|
512
513
|
if (!sourceManager.waitingLogged) {
|
|
@@ -569,7 +570,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
|
|
|
569
570
|
if (s !== undefined) {
|
|
570
571
|
if (s.source !== sourceManager.activeSource) {
|
|
571
572
|
let logger = Logging.createChild({
|
|
572
|
-
chainId: sourceManager.activeSource.
|
|
573
|
+
chainId: sourceManager.activeSource.chainId
|
|
573
574
|
});
|
|
574
575
|
Logging.childInfo(logger, {
|
|
575
576
|
msg: "Switching data-source",
|
|
@@ -581,7 +582,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
|
|
|
581
582
|
sourceState = s;
|
|
582
583
|
} else {
|
|
583
584
|
let logger$1 = Logging.createChild({
|
|
584
|
-
chainId: sourceManager.activeSource.
|
|
585
|
+
chainId: sourceManager.activeSource.chainId
|
|
585
586
|
});
|
|
586
587
|
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);
|
|
587
588
|
}
|
|
@@ -590,7 +591,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
|
|
|
590
591
|
let toBlock = toBlockRef;
|
|
591
592
|
let retry = retryRef;
|
|
592
593
|
let logger$2 = Logging.createChild({
|
|
593
|
-
chainId: source.
|
|
594
|
+
chainId: source.chainId,
|
|
594
595
|
logType: "Block Range Query",
|
|
595
596
|
partitionId: query.partitionId,
|
|
596
597
|
source: source.name,
|
|
@@ -600,7 +601,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
|
|
|
600
601
|
retry: retry
|
|
601
602
|
});
|
|
602
603
|
try {
|
|
603
|
-
let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addresses, knownHeight, query.partitionId, query.selection, query.itemsTarget, retry, logger$2);
|
|
604
|
+
let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addresses, knownHeight, query.partitionId, FetchState.narrowSelectionToRange(query.selection, toBlock), query.itemsTarget, retry, logger$2);
|
|
604
605
|
recordRequestStats(sourceState, response.requestStats);
|
|
605
606
|
sourceState.lastFailedAt = undefined;
|
|
606
607
|
if (response.knownHeight > sourceState.knownHeight) {
|
|
@@ -725,7 +726,7 @@ async function getBlockHashes(sourceManager, blockNumbers, isRealtime) {
|
|
|
725
726
|
sourceState = s;
|
|
726
727
|
} else {
|
|
727
728
|
let logger = Logging.createChild({
|
|
728
|
-
chainId: sourceManager.activeSource.
|
|
729
|
+
chainId: sourceManager.activeSource.chainId
|
|
729
730
|
});
|
|
730
731
|
sourceState = ErrorHandling.mkLogAndRaise(logger, "No data-sources available for fetching block hashes.", null);
|
|
731
732
|
}
|
|
@@ -733,7 +734,7 @@ async function getBlockHashes(sourceManager, blockNumbers, isRealtime) {
|
|
|
733
734
|
let source = sourceState.source;
|
|
734
735
|
let retry = retryRef;
|
|
735
736
|
let logger$1 = Logging.createChild({
|
|
736
|
-
chainId: source.
|
|
737
|
+
chainId: source.chainId,
|
|
737
738
|
logType: "Block Hash Query",
|
|
738
739
|
source: source.name,
|
|
739
740
|
retry: retry
|
|
@@ -23,7 +23,7 @@ let getActiveSource: t => Source.t
|
|
|
23
23
|
|
|
24
24
|
type requestStatSample = {
|
|
25
25
|
sourceName: string,
|
|
26
|
-
chainId:
|
|
26
|
+
chainId: ChainId.t,
|
|
27
27
|
method: string,
|
|
28
28
|
count: int,
|
|
29
29
|
seconds: float,
|
|
@@ -33,7 +33,7 @@ let getRequestStatSamples: t => array<requestStatSample>
|
|
|
33
33
|
|
|
34
34
|
type sourceHeightSample = {
|
|
35
35
|
sourceName: string,
|
|
36
|
-
chainId:
|
|
36
|
+
chainId: ChainId.t,
|
|
37
37
|
height: int,
|
|
38
38
|
}
|
|
39
39
|
|
package/src/sources/Svm.res
CHANGED
|
@@ -50,7 +50,7 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
50
50
|
~params={
|
|
51
51
|
"program": eventItem.onEventRegistration.eventConfig.contractName,
|
|
52
52
|
"instruction": eventItem.onEventRegistration.eventConfig.name,
|
|
53
|
-
"chainId": eventItem.
|
|
53
|
+
"chainId": eventItem.chainId,
|
|
54
54
|
"slot": eventItem.blockNumber,
|
|
55
55
|
"programId": instruction.programId,
|
|
56
56
|
},
|
|
@@ -70,14 +70,13 @@ module GetFinalizedSlot = {
|
|
|
70
70
|
)
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
let makeRPCSource = (~
|
|
73
|
+
let makeRPCSource = (~chainId, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): Source.t => {
|
|
74
74
|
let client = Rest.client(rpc)
|
|
75
|
-
let chainId = chain->ChainMap.Chain.toChainId
|
|
76
75
|
|
|
77
76
|
let urlHost = switch Utils.Url.getHostFromUrl(rpc) {
|
|
78
77
|
| None =>
|
|
79
78
|
JsError.throwWithMessage(
|
|
80
|
-
`The RPC url for chain ${chainId->
|
|
79
|
+
`The RPC url for chain ${chainId->ChainId.toString} is in incorrect format. The RPC url needs to start with either http:// or https://`,
|
|
81
80
|
)
|
|
82
81
|
| Some(host) => host
|
|
83
82
|
}
|
|
@@ -86,7 +85,7 @@ let makeRPCSource = (~chain, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): S
|
|
|
86
85
|
{
|
|
87
86
|
name,
|
|
88
87
|
sourceFor,
|
|
89
|
-
|
|
88
|
+
chainId,
|
|
90
89
|
poweredByHyperSync: false,
|
|
91
90
|
pollingInterval: 10_000,
|
|
92
91
|
getBlockHashes: (~blockNumbers as _, ~logger as _) =>
|
package/src/sources/Svm.res.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as Rpc from "./Rpc.res.mjs";
|
|
4
4
|
import * as Rest from "../vendored/Rest.res.mjs";
|
|
5
5
|
import * as Utils from "../Utils.res.mjs";
|
|
6
|
+
import * as ChainId from "../ChainId.res.mjs";
|
|
6
7
|
import * as Logging from "../Logging.res.mjs";
|
|
7
8
|
import * as Internal from "../Internal.res.mjs";
|
|
8
9
|
import * as BlockStore from "./BlockStore.res.mjs";
|
|
@@ -47,7 +48,7 @@ function make(logger) {
|
|
|
47
48
|
return Logging.createChildFrom(logger, {
|
|
48
49
|
program: eventItem.onEventRegistration.eventConfig.contractName,
|
|
49
50
|
instruction: eventItem.onEventRegistration.eventConfig.name,
|
|
50
|
-
chainId: eventItem.
|
|
51
|
+
chainId: eventItem.chainId,
|
|
51
52
|
slot: eventItem.blockNumber,
|
|
52
53
|
programId: instruction.programId
|
|
53
54
|
});
|
|
@@ -66,16 +67,16 @@ let GetFinalizedSlot = {
|
|
|
66
67
|
route: route
|
|
67
68
|
};
|
|
68
69
|
|
|
69
|
-
function makeRPCSource(
|
|
70
|
+
function makeRPCSource(chainId, rpc, sourceForOpt) {
|
|
70
71
|
let sourceFor = sourceForOpt !== undefined ? sourceForOpt : "Sync";
|
|
71
72
|
let client = Rest.client(rpc, undefined);
|
|
72
73
|
let host = Utils.Url.getHostFromUrl(rpc);
|
|
73
|
-
let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` +
|
|
74
|
+
let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` + ChainId.toString(chainId) + ` is in incorrect format. The RPC url needs to start with either http:// or https://`);
|
|
74
75
|
let name = `RPC (` + urlHost + `)`;
|
|
75
76
|
return {
|
|
76
77
|
name: name,
|
|
77
78
|
sourceFor: sourceFor,
|
|
78
|
-
|
|
79
|
+
chainId: chainId,
|
|
79
80
|
poweredByHyperSync: false,
|
|
80
81
|
pollingInterval: 10000,
|
|
81
82
|
getBlockHashes: (param, param$1) => Stdlib_JsError.throwWithMessage("Svm does not support getting block hashes"),
|
|
@@ -25,6 +25,8 @@ module Registration = {
|
|
|
25
25
|
contractName: string,
|
|
26
26
|
programId: string,
|
|
27
27
|
isWildcard: bool,
|
|
28
|
+
// Earliest slot this registration accepts; `None` is unrestricted.
|
|
29
|
+
startBlock: option<int>,
|
|
28
30
|
discriminator?: string,
|
|
29
31
|
discriminatorByteLen: int,
|
|
30
32
|
isInner?: bool,
|
|
@@ -52,6 +54,7 @@ module Registration = {
|
|
|
52
54
|
contractName: eventConfig.contractName,
|
|
53
55
|
programId: eventConfig.programId->SvmTypes.Pubkey.toString,
|
|
54
56
|
isWildcard: reg.isWildcard,
|
|
57
|
+
startBlock: reg.startBlock,
|
|
55
58
|
discriminator: ?eventConfig.discriminator,
|
|
56
59
|
discriminatorByteLen: eventConfig.discriminatorByteLen,
|
|
57
60
|
isInner: ?eventConfig.isInner,
|
|
@@ -18,6 +18,7 @@ function fromOnEventRegistrations(onEventRegistrations) {
|
|
|
18
18
|
contractName: eventConfig.contractName,
|
|
19
19
|
programId: eventConfig.programId,
|
|
20
20
|
isWildcard: reg.isWildcard,
|
|
21
|
+
startBlock: reg.startBlock,
|
|
21
22
|
discriminator: eventConfig.discriminator,
|
|
22
23
|
discriminatorByteLen: eventConfig.discriminatorByteLen,
|
|
23
24
|
isInner: eventConfig.isInner,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
open Source
|
|
2
2
|
|
|
3
3
|
type options = {
|
|
4
|
-
|
|
4
|
+
chainId: ChainId.t,
|
|
5
5
|
endpointUrl: string,
|
|
6
6
|
apiToken: option<string>,
|
|
7
7
|
onEventRegistrations: array<Internal.svmOnEventRegistration>,
|
|
@@ -68,7 +68,7 @@ let toSvmInstruction = (
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
let make = (
|
|
71
|
-
{
|
|
71
|
+
{chainId, endpointUrl, apiToken, onEventRegistrations, clientTimeoutMillis, addressStore}: options,
|
|
72
72
|
): t => {
|
|
73
73
|
let name = "SvmHyperSync"
|
|
74
74
|
|
|
@@ -159,7 +159,7 @@ let make = (
|
|
|
159
159
|
)
|
|
160
160
|
Internal.Event({
|
|
161
161
|
onEventRegistration,
|
|
162
|
-
|
|
162
|
+
chainId,
|
|
163
163
|
blockNumber: item.slot,
|
|
164
164
|
logIndex: synthLogIndex(
|
|
165
165
|
~transactionIndex=item.transactionIndex,
|
|
@@ -283,7 +283,7 @@ let make = (
|
|
|
283
283
|
{
|
|
284
284
|
name,
|
|
285
285
|
sourceFor: Sync,
|
|
286
|
-
|
|
286
|
+
chainId,
|
|
287
287
|
pollingInterval: 1000,
|
|
288
288
|
poweredByHyperSync: true,
|
|
289
289
|
getBlockHashes,
|
|
@@ -57,7 +57,7 @@ function toSvmInstruction(item, programName, instructionName) {
|
|
|
57
57
|
|
|
58
58
|
function make(param) {
|
|
59
59
|
let onEventRegistrations = param.onEventRegistrations;
|
|
60
|
-
let
|
|
60
|
+
let chainId = param.chainId;
|
|
61
61
|
let client = SvmHyperSyncClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, undefined, undefined, undefined, SvmHyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations), param.addressStore);
|
|
62
62
|
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, knownHeight, param, selection, itemsTarget, retry, param$1) => {
|
|
63
63
|
let totalTimeRef = Performance.now();
|
|
@@ -113,7 +113,7 @@ function make(param) {
|
|
|
113
113
|
return {
|
|
114
114
|
kind: 0,
|
|
115
115
|
onEventRegistration: onEventRegistration,
|
|
116
|
-
|
|
116
|
+
chainId: chainId,
|
|
117
117
|
blockNumber: item.slot,
|
|
118
118
|
logIndex: synthLogIndex(item.transactionIndex, item.instructionAddress),
|
|
119
119
|
transactionIndex: item.transactionIndex,
|
|
@@ -243,7 +243,7 @@ function make(param) {
|
|
|
243
243
|
return {
|
|
244
244
|
name: "SvmHyperSync",
|
|
245
245
|
sourceFor: "Sync",
|
|
246
|
-
|
|
246
|
+
chainId: chainId,
|
|
247
247
|
poweredByHyperSync: true,
|
|
248
248
|
pollingInterval: 1000,
|
|
249
249
|
getBlockHashes: getBlockHashes,
|
package/src/tui/Tui.res
CHANGED
|
@@ -204,7 +204,7 @@ module App = {
|
|
|
204
204
|
knownHeight: data.knownHeight,
|
|
205
205
|
latestFetchedBlockNumber,
|
|
206
206
|
eventsProcessed: numEventsProcessed,
|
|
207
|
-
chainId: (cs->ChainState.chainConfig).id->
|
|
207
|
+
chainId: (cs->ChainState.chainConfig).id->ChainId.toString,
|
|
208
208
|
progressBlock: committedProgressBlockNumber < data.startBlock
|
|
209
209
|
? Some(data.startBlock)
|
|
210
210
|
: Some(committedProgressBlockNumber),
|
package/src/tui/Tui.res.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import * as Env from "../Env.res.mjs";
|
|
|
4
4
|
import * as Ink from "./bindings/Ink.res.mjs";
|
|
5
5
|
import * as Ink$1 from "ink";
|
|
6
6
|
import * as React from "react";
|
|
7
|
+
import * as ChainId from "../ChainId.res.mjs";
|
|
7
8
|
import * as SyncETA from "./components/SyncETA.res.mjs";
|
|
8
9
|
import * as TuiData from "./components/TuiData.res.mjs";
|
|
9
10
|
import * as Messages from "./components/Messages.res.mjs";
|
|
@@ -255,7 +256,7 @@ function Tui$App(props) {
|
|
|
255
256
|
break;
|
|
256
257
|
}
|
|
257
258
|
return {
|
|
258
|
-
chainId: ChainState.chainConfig(cs).id
|
|
259
|
+
chainId: ChainId.toString(ChainState.chainConfig(cs).id),
|
|
259
260
|
eventsProcessed: numEventsProcessed,
|
|
260
261
|
progressBlock: committedProgressBlockNumber < data.startBlock ? data.startBlock : committedProgressBlockNumber,
|
|
261
262
|
bufferBlock: latestFetchedBlockNumber,
|
|
@@ -4,16 +4,16 @@ module InitApi = {
|
|
|
4
4
|
envioVersion: string,
|
|
5
5
|
envioApiToken: option<string>,
|
|
6
6
|
ecosystem: ecosystem,
|
|
7
|
-
hyperSyncNetworks: array<
|
|
8
|
-
rpcNetworks: array<
|
|
7
|
+
hyperSyncNetworks: array<ChainId.t>,
|
|
8
|
+
rpcNetworks: array<ChainId.t>,
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
let bodySchema = S.object(s => {
|
|
12
12
|
envioVersion: s.field("envioVersion", S.string),
|
|
13
13
|
envioApiToken: s.field("envioApiToken", S.option(S.string)),
|
|
14
14
|
ecosystem: s.field("ecosystem", S.enum([Evm, Fuel, Svm])),
|
|
15
|
-
hyperSyncNetworks: s.field("hyperSyncNetworks", S.array(
|
|
16
|
-
rpcNetworks: s.field("rpcNetworks", S.array(
|
|
15
|
+
hyperSyncNetworks: s.field("hyperSyncNetworks", S.array(ChainId.schema)),
|
|
16
|
+
rpcNetworks: s.field("rpcNetworks", S.array(ChainId.schema)),
|
|
17
17
|
})
|
|
18
18
|
|
|
19
19
|
let makeBody = (~envioVersion, ~envioApiToken, ~config: Config.t) => {
|
|
@@ -28,6 +28,7 @@ module InitApi = {
|
|
|
28
28
|
| Config.EvmSourceConfig({hypersync: None}) => false
|
|
29
29
|
| Config.FuelSourceConfig(_) => true // Fuel always uses HyperFuel
|
|
30
30
|
| Config.SvmSourceConfig(_) => false
|
|
31
|
+
| Config.SimulateSourceConfig(_) => false
|
|
31
32
|
| Config.CustomSources(sources) => sources->Array.some(s => s.poweredByHyperSync)
|
|
32
33
|
}
|
|
33
34
|
switch usesHyperSync {
|
|
@@ -4,6 +4,7 @@ import * as Env from "../../Env.res.mjs";
|
|
|
4
4
|
import * as Rest from "../../vendored/Rest.res.mjs";
|
|
5
5
|
import * as Utils from "../../Utils.res.mjs";
|
|
6
6
|
import * as React from "react";
|
|
7
|
+
import * as ChainId from "../../ChainId.res.mjs";
|
|
7
8
|
import * as Logging from "../../Logging.res.mjs";
|
|
8
9
|
import * as ChainMap from "../../ChainMap.res.mjs";
|
|
9
10
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -17,8 +18,8 @@ let bodySchema = S$RescriptSchema.object(s => ({
|
|
|
17
18
|
"fuel",
|
|
18
19
|
"svm"
|
|
19
20
|
])),
|
|
20
|
-
hyperSyncNetworks: s.f("hyperSyncNetworks", S$RescriptSchema.array(
|
|
21
|
-
rpcNetworks: s.f("rpcNetworks", S$RescriptSchema.array(
|
|
21
|
+
hyperSyncNetworks: s.f("hyperSyncNetworks", S$RescriptSchema.array(ChainId.schema)),
|
|
22
|
+
rpcNetworks: s.f("rpcNetworks", S$RescriptSchema.array(ChainId.schema))
|
|
22
23
|
}));
|
|
23
24
|
|
|
24
25
|
function makeBody(envioVersion, envioApiToken, config) {
|
|
@@ -35,6 +36,7 @@ function makeBody(envioVersion, envioApiToken, config) {
|
|
|
35
36
|
usesHyperSync = true;
|
|
36
37
|
break;
|
|
37
38
|
case "SvmSourceConfig" :
|
|
39
|
+
case "SimulateSourceConfig" :
|
|
38
40
|
usesHyperSync = false;
|
|
39
41
|
break;
|
|
40
42
|
case "CustomSources" :
|