envio 3.3.0-alpha.1 → 3.3.0-alpha.11
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 +10 -0
- package/index.d.ts +45 -25
- package/licenses/CLA.md +35 -0
- package/licenses/EULA.md +67 -0
- package/licenses/LICENSE.md +45 -0
- package/licenses/README.md +35 -0
- package/package.json +10 -9
- package/src/Address.res +5 -2
- package/src/Address.res.mjs +3 -1
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/Batch.res +0 -6
- package/src/Batch.res.mjs +1 -12
- package/src/BatchProcessing.res +7 -12
- package/src/BatchProcessing.res.mjs +8 -7
- package/src/Bin.res +3 -0
- package/src/Bin.res.mjs +4 -0
- package/src/ChainFetching.res +53 -16
- package/src/ChainFetching.res.mjs +37 -19
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +630 -161
- package/src/ChainState.res.mjs +438 -101
- package/src/ChainState.resi +77 -4
- package/src/Config.res +70 -38
- package/src/Config.res.mjs +52 -12
- package/src/ContractRegisterContext.res +2 -12
- package/src/ContractRegisterContext.res.mjs +3 -5
- package/src/Core.res +34 -3
- package/src/Core.res.mjs +12 -0
- package/src/CrossChainState.res +130 -89
- package/src/CrossChainState.res.mjs +66 -61
- package/src/CrossChainState.resi +1 -1
- package/src/Ecosystem.res +5 -6
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Envio.res +17 -11
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +191 -127
- package/src/EventConfigBuilder.res.mjs +116 -66
- package/src/EventProcessing.res +77 -28
- package/src/EventProcessing.res.mjs +56 -29
- package/src/ExitOnCaughtUp.res +10 -2
- package/src/ExitOnCaughtUp.res.mjs +10 -1
- package/src/FetchState.res +684 -415
- package/src/FetchState.res.mjs +505 -486
- package/src/HandlerLoader.res +8 -104
- package/src/HandlerLoader.res.mjs +2 -81
- package/src/HandlerRegister.res +520 -144
- package/src/HandlerRegister.res.mjs +286 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerState.res +10 -3
- package/src/IndexerState.res.mjs +11 -4
- package/src/IndexerState.resi +2 -1
- package/src/IndexingAddresses.res +108 -0
- package/src/IndexingAddresses.res.mjs +101 -0
- package/src/IndexingAddresses.resi +34 -0
- package/src/Internal.res +166 -48
- package/src/Internal.res.mjs +30 -2
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/LogSelection.res +92 -217
- package/src/LogSelection.res.mjs +95 -184
- package/src/Main.res +71 -236
- package/src/Main.res.mjs +60 -145
- package/src/Metrics.res +74 -0
- package/src/Metrics.res.mjs +75 -0
- package/src/PgStorage.res +4 -4
- package/src/PgStorage.res.mjs +5 -5
- package/src/Prometheus.res +10 -63
- package/src/Prometheus.res.mjs +124 -171
- package/src/PruneStaleHistory.res +2 -2
- package/src/PruneStaleHistory.res.mjs +3 -3
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/Rollback.res +3 -3
- package/src/Rollback.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateDeadInputTracker.res +85 -0
- package/src/SimulateDeadInputTracker.res.mjs +73 -0
- package/src/SimulateDeadInputTracker.resi +12 -0
- package/src/SimulateItems.res +128 -28
- package/src/SimulateItems.res.mjs +82 -40
- package/src/TestIndexer.res +55 -41
- package/src/TestIndexer.res.mjs +39 -32
- package/src/TopicFilter.res +1 -25
- package/src/TopicFilter.res.mjs +0 -74
- package/src/bindings/Performance.res +7 -0
- package/src/bindings/Performance.res.mjs +21 -0
- package/src/bindings/Performance.resi +7 -0
- package/src/bindings/Viem.res +0 -46
- package/src/bindings/Viem.res.mjs +1 -43
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +31 -49
- package/src/sources/EventRouter.res.mjs +12 -25
- package/src/sources/Evm.res +83 -72
- package/src/sources/Evm.res.mjs +53 -69
- package/src/sources/EvmChain.res +7 -34
- package/src/sources/EvmChain.res.mjs +6 -27
- package/src/sources/EvmRpcClient.res +71 -5
- package/src/sources/EvmRpcClient.res.mjs +13 -4
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +9 -6
- package/src/sources/Fuel.res.mjs +5 -10
- package/src/sources/HyperFuelSource.res +46 -50
- package/src/sources/HyperFuelSource.res.mjs +64 -54
- package/src/sources/HyperSync.res +45 -42
- package/src/sources/HyperSync.res.mjs +68 -60
- package/src/sources/HyperSync.resi +14 -4
- package/src/sources/HyperSyncClient.res +107 -119
- package/src/sources/HyperSyncClient.res.mjs +36 -31
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +60 -254
- package/src/sources/HyperSyncSource.res.mjs +57 -180
- package/src/sources/Rpc.res +15 -79
- package/src/sources/Rpc.res.mjs +25 -101
- package/src/sources/RpcSource.res +221 -514
- package/src/sources/RpcSource.res.mjs +216 -411
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +44 -20
- package/src/sources/SimulateSource.res.mjs +41 -14
- package/src/sources/Source.res +34 -6
- package/src/sources/SourceManager.res +77 -19
- package/src/sources/SourceManager.res.mjs +63 -21
- package/src/sources/SourceManager.resi +10 -0
- package/src/sources/Svm.res +31 -16
- package/src/sources/Svm.res.mjs +36 -13
- package/src/sources/SvmHyperSyncClient.res +5 -32
- package/src/sources/SvmHyperSyncSource.res +159 -134
- package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
- package/src/sources/TransactionStore.res +49 -0
- package/src/sources/TransactionStore.res.mjs +30 -0
- package/src/tui/Tui.res +13 -16
- package/src/tui/Tui.res.mjs +12 -14
- package/svm.schema.json +49 -37
- package/src/bindings/Hrtime.res +0 -58
- package/src/bindings/Hrtime.res.mjs +0 -90
- package/src/bindings/Hrtime.resi +0 -30
|
@@ -4,15 +4,14 @@ import * as Time from "../Time.res.mjs";
|
|
|
4
4
|
import * as Utils from "../Utils.res.mjs";
|
|
5
5
|
import * as Source from "./Source.res.mjs";
|
|
6
6
|
import * as Logging from "../Logging.res.mjs";
|
|
7
|
-
import * as Prometheus from "../Prometheus.res.mjs";
|
|
8
7
|
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
8
|
+
import * as Performance from "../bindings/Performance.res.mjs";
|
|
9
9
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
10
10
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
11
11
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
12
12
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
13
13
|
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
14
14
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
15
|
-
import * as HyperSyncClient from "./HyperSyncClient.res.mjs";
|
|
16
15
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
17
16
|
|
|
18
17
|
function reraisIfRateLimited(exn) {
|
|
@@ -62,15 +61,6 @@ function mapExn(queryResponse) {
|
|
|
62
61
|
|
|
63
62
|
let $$Error = /* @__PURE__ */Primitive_exceptions.create("HyperSync.GetLogs.Error");
|
|
64
63
|
|
|
65
|
-
function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, fieldSelection) {
|
|
66
|
-
return {
|
|
67
|
-
fromBlock: fromBlock,
|
|
68
|
-
toBlock: toBlockInclusive !== undefined ? toBlockInclusive + 1 | 0 : undefined,
|
|
69
|
-
logs: addressesWithTopics,
|
|
70
|
-
fieldSelection: fieldSelection
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
64
|
function extractMissingParams(exn) {
|
|
75
65
|
let message = exn.RE_EXN_ID === "JsExn" ? Stdlib_JsExn.message(exn._1) : undefined;
|
|
76
66
|
if (message === undefined) {
|
|
@@ -92,18 +82,17 @@ function extractMissingParams(exn) {
|
|
|
92
82
|
}
|
|
93
83
|
}
|
|
94
84
|
|
|
95
|
-
async function query(client, fromBlock, toBlock,
|
|
96
|
-
let
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
let
|
|
104
|
-
let res;
|
|
85
|
+
async function query(client, fromBlock, toBlock, maxNumLogs, registrationIndexes, addressesByContractName) {
|
|
86
|
+
let query$1 = {
|
|
87
|
+
fromBlock: fromBlock,
|
|
88
|
+
toBlock: toBlock,
|
|
89
|
+
maxNumLogs: maxNumLogs,
|
|
90
|
+
registrationIndexes: registrationIndexes,
|
|
91
|
+
addressesByContractName: addressesByContractName
|
|
92
|
+
};
|
|
93
|
+
let match;
|
|
105
94
|
try {
|
|
106
|
-
|
|
95
|
+
match = await client.getEventItems(query$1);
|
|
107
96
|
} catch (raw_exn) {
|
|
108
97
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
109
98
|
reraisIfRateLimited(exn);
|
|
@@ -120,6 +109,7 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
|
|
|
120
109
|
}
|
|
121
110
|
throw exn;
|
|
122
111
|
}
|
|
112
|
+
let res = match[0];
|
|
123
113
|
if (res.nextBlock <= fromBlock) {
|
|
124
114
|
throw {
|
|
125
115
|
RE_EXN_ID: $$Error,
|
|
@@ -129,13 +119,22 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
|
|
|
129
119
|
}
|
|
130
120
|
return {
|
|
131
121
|
items: res.items,
|
|
122
|
+
blocks: res.blocks,
|
|
132
123
|
nextBlock: res.nextBlock,
|
|
133
124
|
archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
|
|
134
|
-
rollbackGuard: res.rollbackGuard
|
|
125
|
+
rollbackGuard: res.rollbackGuard,
|
|
126
|
+
transactionStore: match[1],
|
|
127
|
+
blockStore: match[2]
|
|
135
128
|
};
|
|
136
129
|
}
|
|
137
130
|
|
|
138
|
-
|
|
131
|
+
let GetLogs = {
|
|
132
|
+
$$Error: $$Error,
|
|
133
|
+
extractMissingParams: extractMissingParams,
|
|
134
|
+
query: query
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
function makeRequestBody(fromBlock, toBlock) {
|
|
139
138
|
return {
|
|
140
139
|
fromBlock: fromBlock,
|
|
141
140
|
toBlock: toBlock + 1 | 0,
|
|
@@ -187,14 +186,14 @@ function convertResponse(res) {
|
|
|
187
186
|
}));
|
|
188
187
|
}
|
|
189
188
|
|
|
190
|
-
async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger) {
|
|
191
|
-
let body = makeRequestBody
|
|
189
|
+
async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats) {
|
|
190
|
+
let body = makeRequestBody(fromBlock, toBlock);
|
|
192
191
|
let logger$1 = Logging.createChildFrom(logger, {
|
|
193
192
|
logType: "HyperSync get block hash query",
|
|
194
193
|
fromBlock: fromBlock,
|
|
195
194
|
toBlock: toBlock
|
|
196
195
|
});
|
|
197
|
-
|
|
196
|
+
let timerRef = Performance.now();
|
|
198
197
|
let maybeSuccessfulRes;
|
|
199
198
|
let exit = 0;
|
|
200
199
|
let res;
|
|
@@ -209,6 +208,10 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
|
|
|
209
208
|
if (exit === 1) {
|
|
210
209
|
maybeSuccessfulRes = res.nextBlock <= fromBlock ? undefined : res;
|
|
211
210
|
}
|
|
211
|
+
requestStats.push({
|
|
212
|
+
method: "getBlockHashes",
|
|
213
|
+
seconds: Performance.secondsSince(timerRef)
|
|
214
|
+
});
|
|
212
215
|
if (maybeSuccessfulRes !== undefined) {
|
|
213
216
|
let err = convertResponse(maybeSuccessfulRes);
|
|
214
217
|
if (err.TAG !== "Ok") {
|
|
@@ -218,56 +221,61 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
|
|
|
218
221
|
return err;
|
|
219
222
|
}
|
|
220
223
|
let datas = err._0;
|
|
221
|
-
let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1);
|
|
224
|
+
let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1, requestStats);
|
|
222
225
|
return Stdlib_Result.map(restRes, rest => datas.concat(rest));
|
|
223
226
|
}
|
|
224
227
|
Logging.childInfo(logger$1, `Block #` + fromBlock.toString() + ` not found in HyperSync. HyperSync has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in ` + (100).toString() + `ms.`);
|
|
225
228
|
await Time.resolvePromiseAfterDelay(100);
|
|
226
|
-
return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1);
|
|
229
|
+
return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1, requestStats);
|
|
227
230
|
}
|
|
228
231
|
|
|
229
232
|
async function queryBlockDataMulti(client, blockNumbers, sourceName, chainId, logger) {
|
|
233
|
+
let requestStats = [];
|
|
230
234
|
let firstBlock = blockNumbers[0];
|
|
231
|
-
|
|
232
|
-
|
|
235
|
+
let result;
|
|
236
|
+
if (firstBlock !== undefined) {
|
|
237
|
+
let fromBlock = firstBlock;
|
|
238
|
+
let toBlock = firstBlock;
|
|
239
|
+
let set = new Set();
|
|
240
|
+
for (let idx = 0, idx_finish = blockNumbers.length; idx < idx_finish; ++idx) {
|
|
241
|
+
let blockNumber = blockNumbers[idx];
|
|
242
|
+
if (blockNumber < fromBlock) {
|
|
243
|
+
fromBlock = blockNumber;
|
|
244
|
+
}
|
|
245
|
+
if (blockNumber > toBlock) {
|
|
246
|
+
toBlock = blockNumber;
|
|
247
|
+
}
|
|
248
|
+
set.add(blockNumber);
|
|
249
|
+
}
|
|
250
|
+
if ((toBlock - fromBlock | 0) > 1000) {
|
|
251
|
+
Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
|
|
252
|
+
}
|
|
253
|
+
let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats);
|
|
254
|
+
let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
|
|
255
|
+
if (set.size > 0) {
|
|
256
|
+
Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
|
|
257
|
+
}
|
|
258
|
+
result = filtered;
|
|
259
|
+
} else {
|
|
260
|
+
result = {
|
|
233
261
|
TAG: "Ok",
|
|
234
262
|
_0: []
|
|
235
263
|
};
|
|
236
264
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
let blockNumber = blockNumbers[idx];
|
|
242
|
-
if (blockNumber < fromBlock) {
|
|
243
|
-
fromBlock = blockNumber;
|
|
244
|
-
}
|
|
245
|
-
if (blockNumber > toBlock) {
|
|
246
|
-
toBlock = blockNumber;
|
|
247
|
-
}
|
|
248
|
-
set.add(blockNumber);
|
|
249
|
-
}
|
|
250
|
-
if ((toBlock - fromBlock | 0) > 1000) {
|
|
251
|
-
Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
|
|
252
|
-
}
|
|
253
|
-
let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger);
|
|
254
|
-
let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
|
|
255
|
-
if (set.size > 0) {
|
|
256
|
-
Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
|
|
257
|
-
}
|
|
258
|
-
return filtered;
|
|
265
|
+
return [
|
|
266
|
+
result,
|
|
267
|
+
requestStats
|
|
268
|
+
];
|
|
259
269
|
}
|
|
260
270
|
|
|
261
271
|
function queryBlockData$1(client, blockNumber, sourceName, chainId, logger) {
|
|
262
|
-
|
|
272
|
+
let requestStats = [];
|
|
273
|
+
return queryBlockData(client, blockNumber, blockNumber, sourceName, chainId, logger, requestStats).then(res => [
|
|
274
|
+
Stdlib_Result.map(res, res => res[0]),
|
|
275
|
+
requestStats
|
|
276
|
+
]);
|
|
263
277
|
}
|
|
264
278
|
|
|
265
|
-
let GetLogs = {
|
|
266
|
-
$$Error: $$Error,
|
|
267
|
-
extractMissingParams: extractMissingParams,
|
|
268
|
-
query: query
|
|
269
|
-
};
|
|
270
|
-
|
|
271
279
|
export {
|
|
272
280
|
queryErrorToMsq,
|
|
273
281
|
GetLogs,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
type logsQueryPage = {
|
|
2
2
|
items: array<HyperSyncClient.EventItems.item>,
|
|
3
|
+
blocks: array<HyperSyncClient.EventItems.blockHeader>,
|
|
3
4
|
nextBlock: int,
|
|
4
5
|
archiveHeight: int,
|
|
5
6
|
rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
|
|
7
|
+
transactionStore: TransactionStore.t,
|
|
8
|
+
blockStore: BlockStore.t,
|
|
6
9
|
}
|
|
7
10
|
|
|
8
11
|
type missingParams = {
|
|
@@ -29,8 +32,9 @@ module GetLogs: {
|
|
|
29
32
|
~client: HyperSyncClient.t,
|
|
30
33
|
~fromBlock: int,
|
|
31
34
|
~toBlock: option<int>,
|
|
32
|
-
~
|
|
33
|
-
~
|
|
35
|
+
~maxNumLogs: int,
|
|
36
|
+
~registrationIndexes: array<int>,
|
|
37
|
+
~addressesByContractName: dict<array<Address.t>>,
|
|
34
38
|
) => promise<logsQueryPage>
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -40,7 +44,10 @@ let queryBlockData: (
|
|
|
40
44
|
~sourceName: string,
|
|
41
45
|
~chainId: int,
|
|
42
46
|
~logger: Pino.t,
|
|
43
|
-
) => promise<
|
|
47
|
+
) => promise<(
|
|
48
|
+
queryResponse<option<ReorgDetection.blockDataWithTimestamp>>,
|
|
49
|
+
array<Source.requestStat>,
|
|
50
|
+
)>
|
|
44
51
|
|
|
45
52
|
let queryBlockDataMulti: (
|
|
46
53
|
~client: HyperSyncClient.t,
|
|
@@ -48,6 +55,9 @@ let queryBlockDataMulti: (
|
|
|
48
55
|
~sourceName: string,
|
|
49
56
|
~chainId: int,
|
|
50
57
|
~logger: Pino.t,
|
|
51
|
-
) => promise<
|
|
58
|
+
) => promise<(
|
|
59
|
+
queryResponse<array<ReorgDetection.blockDataWithTimestamp>>,
|
|
60
|
+
array<Source.requestStat>,
|
|
61
|
+
)>
|
|
52
62
|
|
|
53
63
|
let mapExn: queryResponse<'a> => result<'a, exn>
|
|
@@ -208,90 +208,6 @@ module ResponseTypes = {
|
|
|
208
208
|
mixHash?: string,
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
type accessList = {
|
|
212
|
-
address?: Address.t,
|
|
213
|
-
storageKeys?: array<string>,
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
let accessListSchema = S.object(s => {
|
|
217
|
-
address: ?s.field("address", S.option(Address.schema)),
|
|
218
|
-
storageKeys: ?s.field("storageKeys", S.option(S.array(S.string))),
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
type authorizationList = {
|
|
222
|
-
chainId: bigint,
|
|
223
|
-
address: Address.t,
|
|
224
|
-
nonce: int,
|
|
225
|
-
yParity: [#0 | #1],
|
|
226
|
-
r: string,
|
|
227
|
-
s: string,
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
let authorizationListSchema = S.object(s => {
|
|
231
|
-
chainId: s.field("chainId", S.bigint),
|
|
232
|
-
address: s.field("address", Address.schema),
|
|
233
|
-
nonce: s.field("nonce", S.int),
|
|
234
|
-
yParity: s.field("yParity", S.enum([#0, #1])),
|
|
235
|
-
r: s.field("r", S.string),
|
|
236
|
-
s: s.field("s", S.string),
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
type transaction = {
|
|
240
|
-
blockHash?: string,
|
|
241
|
-
blockNumber?: int,
|
|
242
|
-
from?: string,
|
|
243
|
-
gas?: bigint,
|
|
244
|
-
gasPrice?: bigint,
|
|
245
|
-
hash?: string,
|
|
246
|
-
input?: string,
|
|
247
|
-
nonce?: bigint,
|
|
248
|
-
to?: string,
|
|
249
|
-
transactionIndex?: int,
|
|
250
|
-
value?: bigint,
|
|
251
|
-
v?: string,
|
|
252
|
-
r?: string,
|
|
253
|
-
s?: string,
|
|
254
|
-
yParity?: string,
|
|
255
|
-
maxPriorityFeePerGas?: bigint,
|
|
256
|
-
maxFeePerGas?: bigint,
|
|
257
|
-
chainId?: int,
|
|
258
|
-
accessList?: array<accessList>,
|
|
259
|
-
maxFeePerBlobGas?: bigint,
|
|
260
|
-
blobVersionedHashes?: array<string>,
|
|
261
|
-
cumulativeGasUsed?: bigint,
|
|
262
|
-
effectiveGasPrice?: bigint,
|
|
263
|
-
gasUsed?: bigint,
|
|
264
|
-
contractAddress?: string,
|
|
265
|
-
logsBloom?: string,
|
|
266
|
-
@as("type") type_?: int,
|
|
267
|
-
root?: string,
|
|
268
|
-
status?: int,
|
|
269
|
-
l1Fee?: bigint,
|
|
270
|
-
l1GasPrice?: bigint,
|
|
271
|
-
l1GasUsed?: bigint,
|
|
272
|
-
l1FeeScalar?: float,
|
|
273
|
-
gasUsedForL1?: bigint,
|
|
274
|
-
authorizationList?: array<authorizationList>,
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
type log = {
|
|
278
|
-
removed?: bool,
|
|
279
|
-
@as("logIndex") index?: int,
|
|
280
|
-
transactionIndex?: int,
|
|
281
|
-
transactionHash?: string,
|
|
282
|
-
blockHash?: string,
|
|
283
|
-
blockNumber?: int,
|
|
284
|
-
address?: Address.t,
|
|
285
|
-
data?: string,
|
|
286
|
-
topics?: array<Nullable.t<EvmTypes.Hex.t>>,
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
type event = {
|
|
290
|
-
transaction?: transaction,
|
|
291
|
-
block?: block,
|
|
292
|
-
log: log,
|
|
293
|
-
}
|
|
294
|
-
|
|
295
211
|
type rollbackGuard = {
|
|
296
212
|
blockNumber: int,
|
|
297
213
|
timestamp: int,
|
|
@@ -303,11 +219,7 @@ module ResponseTypes = {
|
|
|
303
219
|
|
|
304
220
|
type query = QueryTypes.query
|
|
305
221
|
|
|
306
|
-
type queryResponseData = {
|
|
307
|
-
blocks: array<ResponseTypes.block>,
|
|
308
|
-
transactions: array<ResponseTypes.transaction>,
|
|
309
|
-
logs: array<ResponseTypes.log>,
|
|
310
|
-
}
|
|
222
|
+
type queryResponseData = {blocks: array<ResponseTypes.block>}
|
|
311
223
|
|
|
312
224
|
type queryResponse = {
|
|
313
225
|
archiveHeight: option<int>,
|
|
@@ -317,49 +229,121 @@ type queryResponse = {
|
|
|
317
229
|
rollbackGuard: option<ResponseTypes.rollbackGuard>,
|
|
318
230
|
}
|
|
319
231
|
|
|
320
|
-
module
|
|
321
|
-
|
|
232
|
+
module Registration = {
|
|
233
|
+
// One topic position of the resolved `where`: static topic values, or
|
|
234
|
+
// `None` — the "currently registered addresses of this contract" marker,
|
|
235
|
+
// expanded to padded address topics when Rust builds a query.
|
|
236
|
+
type topicFilterInput = option<array<string>>
|
|
237
|
+
|
|
238
|
+
type topicSelectionInput = {
|
|
239
|
+
topic0: array<string>,
|
|
240
|
+
topic1: topicFilterInput,
|
|
241
|
+
topic2: topicFilterInput,
|
|
242
|
+
topic3: topicFilterInput,
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// The full per-(event, chain) registration passed to the Rust clients at
|
|
246
|
+
// construction: decode metadata, routing identity, and the fetch state
|
|
247
|
+
// queries are built from.
|
|
248
|
+
type input = {
|
|
249
|
+
// Chain-scoped sequential registration index, echoed back on routed items.
|
|
250
|
+
index: int,
|
|
322
251
|
sighash: string,
|
|
323
252
|
topicCount: int,
|
|
324
253
|
eventName: string,
|
|
325
254
|
contractName: string,
|
|
255
|
+
isWildcard: bool,
|
|
256
|
+
dependsOnAddresses: bool,
|
|
326
257
|
params: array<Internal.paramMeta>,
|
|
258
|
+
topicSelections: array<topicSelectionInput>,
|
|
259
|
+
// Capitalized field names matching the Rust BlockField/TransactionField
|
|
260
|
+
// string enums.
|
|
261
|
+
blockFields: array<string>,
|
|
262
|
+
transactionFields: array<string>,
|
|
327
263
|
}
|
|
328
264
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
265
|
+
let toTopicFilterInput = (filter: Internal.topicFilter): topicFilterInput =>
|
|
266
|
+
switch filter {
|
|
267
|
+
| Values(values) => Some(values->EvmTypes.Hex.toStrings)
|
|
268
|
+
| ContractAddresses(_) => None
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let fromOnEventRegistrations = (
|
|
272
|
+
onEventRegistrations: array<Internal.evmOnEventRegistration>,
|
|
273
|
+
): array<input> => {
|
|
274
|
+
onEventRegistrations->Array.map(reg => {
|
|
275
|
+
let event = reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.evmEventConfig)
|
|
276
|
+
{
|
|
277
|
+
index: reg.index,
|
|
278
|
+
sighash: event.sighash,
|
|
279
|
+
topicCount: event.topicCount,
|
|
280
|
+
eventName: event.name,
|
|
281
|
+
contractName: event.contractName,
|
|
282
|
+
isWildcard: reg.isWildcard,
|
|
283
|
+
dependsOnAddresses: reg.dependsOnAddresses,
|
|
284
|
+
params: event.paramsMetadata,
|
|
285
|
+
topicSelections: reg.resolvedWhere.topicSelections->Array.map((
|
|
286
|
+
ts
|
|
287
|
+
): topicSelectionInput => {
|
|
288
|
+
topic0: ts.topic0->EvmTypes.Hex.toStrings,
|
|
289
|
+
topic1: ts.topic1->toTopicFilterInput,
|
|
290
|
+
topic2: ts.topic2->toTopicFilterInput,
|
|
291
|
+
topic3: ts.topic3->toTopicFilterInput,
|
|
292
|
+
}),
|
|
293
|
+
// Capitalized to match the Rust BlockField/TransactionField string
|
|
294
|
+
// enums.
|
|
295
|
+
blockFields: event.selectedBlockFields
|
|
296
|
+
->Utils.Set.toArray
|
|
297
|
+
->Array.map(name => (name :> string)->Utils.String.capitalize),
|
|
298
|
+
transactionFields: event.selectedTransactionFields
|
|
299
|
+
->Utils.Set.toArray
|
|
300
|
+
->Array.map(name => (name :> string)->Utils.String.capitalize),
|
|
301
|
+
}
|
|
302
|
+
})
|
|
336
303
|
}
|
|
337
|
-
|
|
338
|
-
@send
|
|
339
|
-
external classFromParams: (
|
|
340
|
-
Core.evmDecoderCtor,
|
|
341
|
-
array<eventParamsInput>,
|
|
342
|
-
~checksumAddresses: bool=?,
|
|
343
|
-
) => tWithParams = "fromParams"
|
|
344
|
-
|
|
345
|
-
let fromParams = (eventParams, ~checksumAddresses=?) =>
|
|
346
|
-
Core.getAddon().evmDecoder->classFromParams(eventParams, ~checksumAddresses?)
|
|
347
304
|
}
|
|
348
305
|
|
|
349
306
|
module EventItems = {
|
|
307
|
+
// The whole per-query input: block range, the partition's registration
|
|
308
|
+
// selection (by id), and its current addresses. Log selections, field
|
|
309
|
+
// selection, and the routing index are derived on the Rust side.
|
|
310
|
+
type query = {
|
|
311
|
+
fromBlock: int,
|
|
312
|
+
// Inclusive; None queries to the end of available data.
|
|
313
|
+
toBlock: option<int>,
|
|
314
|
+
maxNumLogs: int,
|
|
315
|
+
registrationIndexes: array<int>,
|
|
316
|
+
addressesByContractName: dict<array<Address.t>>,
|
|
317
|
+
}
|
|
318
|
+
|
|
350
319
|
type item = {
|
|
351
320
|
logIndex: int,
|
|
352
321
|
srcAddress: Address.t,
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
transaction
|
|
357
|
-
|
|
322
|
+
// Number of the block this log belongs to; the block itself is resolved from
|
|
323
|
+
// `response.blocks`, deduplicated across items sharing a block.
|
|
324
|
+
blockNumber: int,
|
|
325
|
+
// Key (with the block number) into the transaction store; the transaction
|
|
326
|
+
// is resolved from the store on demand.
|
|
327
|
+
transactionIndex: int,
|
|
328
|
+
// The registration this log routed to, by chain-scoped index. Logs that
|
|
329
|
+
// route to no registration never cross the boundary.
|
|
330
|
+
onEventRegistrationIndex: int,
|
|
331
|
+
params: Internal.eventParams,
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// The always-needed block fields, one per block number. The block's remaining
|
|
335
|
+
// fields live raw in the block store and are materialised on demand.
|
|
336
|
+
type blockHeader = {
|
|
337
|
+
number: int,
|
|
338
|
+
timestamp: int,
|
|
339
|
+
hash: string,
|
|
358
340
|
}
|
|
359
341
|
|
|
360
342
|
type response = {
|
|
361
343
|
archiveHeight: option<int>,
|
|
362
344
|
nextBlock: int,
|
|
345
|
+
// One header per block number referenced by `items`.
|
|
346
|
+
blocks: array<blockHeader>,
|
|
363
347
|
items: array<item>,
|
|
364
348
|
rollbackGuard: option<ResponseTypes.rollbackGuard>,
|
|
365
349
|
}
|
|
@@ -367,7 +351,11 @@ module EventItems = {
|
|
|
367
351
|
|
|
368
352
|
type t = {
|
|
369
353
|
get: (~query: query) => promise<queryResponse>,
|
|
370
|
-
|
|
354
|
+
// Returns the response plus page stores owning this page's raw transactions
|
|
355
|
+
// and blocks.
|
|
356
|
+
getEventItems: (
|
|
357
|
+
~query: EventItems.query,
|
|
358
|
+
) => promise<(EventItems.response, TransactionStore.t, BlockStore.t)>,
|
|
371
359
|
getHeight: unit => promise<int>,
|
|
372
360
|
}
|
|
373
361
|
|
|
@@ -376,11 +364,11 @@ external classNew: (
|
|
|
376
364
|
Core.evmHypersyncClientCtor,
|
|
377
365
|
cfg,
|
|
378
366
|
string,
|
|
379
|
-
array<
|
|
367
|
+
array<Registration.input>,
|
|
380
368
|
) => t = "new"
|
|
381
369
|
|
|
382
|
-
let makeWithAgent = (cfg, ~userAgent, ~
|
|
383
|
-
Core.getAddon().evmHypersyncClient->classNew(cfg, userAgent,
|
|
370
|
+
let makeWithAgent = (cfg, ~userAgent, ~eventRegistrations) =>
|
|
371
|
+
Core.getAddon().evmHypersyncClient->classNew(cfg, userAgent, eventRegistrations)
|
|
384
372
|
|
|
385
373
|
type logLevel = [#trace | #debug | #info | #warn | #error]
|
|
386
374
|
let logLevelSchema: S.t<logLevel> = S.enum([#trace, #debug, #info, #warn, #error])
|
|
@@ -398,7 +386,7 @@ let make = (
|
|
|
398
386
|
~url,
|
|
399
387
|
~apiToken,
|
|
400
388
|
~httpReqTimeoutMillis,
|
|
401
|
-
~
|
|
389
|
+
~eventRegistrations,
|
|
402
390
|
~enableChecksumAddresses=true,
|
|
403
391
|
~serializationFormat=?,
|
|
404
392
|
~enableQueryCaching=?,
|
|
@@ -424,6 +412,6 @@ let make = (
|
|
|
424
412
|
logLevel: logLevelToString(logLevel),
|
|
425
413
|
},
|
|
426
414
|
~userAgent=`hyperindex/${envioVersion}`,
|
|
427
|
-
~
|
|
415
|
+
~eventRegistrations,
|
|
428
416
|
)
|
|
429
417
|
}
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Core from "../Core.res.mjs";
|
|
4
4
|
import * as Utils from "../Utils.res.mjs";
|
|
5
|
-
import * as Address from "../Address.res.mjs";
|
|
6
|
-
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
7
5
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
8
6
|
|
|
9
7
|
let serializationFormatSchema = S$RescriptSchema.$$enum([
|
|
@@ -36,40 +34,47 @@ let QueryTypes = {
|
|
|
36
34
|
makeLogSelection: makeLogSelection
|
|
37
35
|
};
|
|
38
36
|
|
|
39
|
-
let
|
|
40
|
-
address: s.f("address", S$RescriptSchema.option(Address.schema)),
|
|
41
|
-
storageKeys: s.f("storageKeys", S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string)))
|
|
42
|
-
}));
|
|
37
|
+
let ResponseTypes = {};
|
|
43
38
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
0,
|
|
50
|
-
1
|
|
51
|
-
])),
|
|
52
|
-
r: s.f("r", S$RescriptSchema.string),
|
|
53
|
-
s: s.f("s", S$RescriptSchema.string)
|
|
54
|
-
}));
|
|
55
|
-
|
|
56
|
-
let ResponseTypes = {
|
|
57
|
-
accessListSchema: accessListSchema,
|
|
58
|
-
authorizationListSchema: authorizationListSchema
|
|
59
|
-
};
|
|
39
|
+
function toTopicFilterInput(filter) {
|
|
40
|
+
if (filter.TAG === "Values") {
|
|
41
|
+
return filter._0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
60
44
|
|
|
61
|
-
function
|
|
62
|
-
return
|
|
45
|
+
function fromOnEventRegistrations(onEventRegistrations) {
|
|
46
|
+
return onEventRegistrations.map(reg => {
|
|
47
|
+
let event = reg.eventConfig;
|
|
48
|
+
return {
|
|
49
|
+
index: reg.index,
|
|
50
|
+
sighash: event.sighash,
|
|
51
|
+
topicCount: event.topicCount,
|
|
52
|
+
eventName: event.name,
|
|
53
|
+
contractName: event.contractName,
|
|
54
|
+
isWildcard: reg.isWildcard,
|
|
55
|
+
dependsOnAddresses: reg.dependsOnAddresses,
|
|
56
|
+
params: event.paramsMetadata,
|
|
57
|
+
topicSelections: reg.resolvedWhere.topicSelections.map(ts => ({
|
|
58
|
+
topic0: ts.topic0,
|
|
59
|
+
topic1: toTopicFilterInput(ts.topic1),
|
|
60
|
+
topic2: toTopicFilterInput(ts.topic2),
|
|
61
|
+
topic3: toTopicFilterInput(ts.topic3)
|
|
62
|
+
})),
|
|
63
|
+
blockFields: Array.from(event.selectedBlockFields).map(name => Utils.$$String.capitalize(name)),
|
|
64
|
+
transactionFields: Array.from(event.selectedTransactionFields).map(name => Utils.$$String.capitalize(name))
|
|
65
|
+
};
|
|
66
|
+
});
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
let
|
|
66
|
-
|
|
69
|
+
let Registration = {
|
|
70
|
+
toTopicFilterInput: toTopicFilterInput,
|
|
71
|
+
fromOnEventRegistrations: fromOnEventRegistrations
|
|
67
72
|
};
|
|
68
73
|
|
|
69
74
|
let EventItems = {};
|
|
70
75
|
|
|
71
|
-
function makeWithAgent(cfg, userAgent,
|
|
72
|
-
return Core.getAddon().EvmHypersyncClient.new(cfg, userAgent,
|
|
76
|
+
function makeWithAgent(cfg, userAgent, eventRegistrations) {
|
|
77
|
+
return Core.getAddon().EvmHypersyncClient.new(cfg, userAgent, eventRegistrations);
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
let logLevelSchema = S$RescriptSchema.$$enum([
|
|
@@ -94,7 +99,7 @@ function logLevelToString(level) {
|
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
|
|
97
|
-
function make(url, apiToken, httpReqTimeoutMillis,
|
|
102
|
+
function make(url, apiToken, httpReqTimeoutMillis, eventRegistrations, enableChecksumAddressesOpt, serializationFormat, enableQueryCaching, retryBaseMs, retryBackoffMs, retryCeilingMs, logLevelOpt) {
|
|
98
103
|
let enableChecksumAddresses = enableChecksumAddressesOpt !== undefined ? enableChecksumAddressesOpt : true;
|
|
99
104
|
let logLevel = logLevelOpt !== undefined ? logLevelOpt : "info";
|
|
100
105
|
let envioVersion = Utils.EnvioPackage.value.version;
|
|
@@ -110,14 +115,14 @@ function make(url, apiToken, httpReqTimeoutMillis, eventParams, enableChecksumAd
|
|
|
110
115
|
serializationFormat: serializationFormat,
|
|
111
116
|
enableQueryCaching: enableQueryCaching,
|
|
112
117
|
logLevel: logLevelToString(logLevel)
|
|
113
|
-
}, `hyperindex/` + envioVersion,
|
|
118
|
+
}, `hyperindex/` + envioVersion, eventRegistrations);
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
export {
|
|
117
122
|
serializationFormatSchema,
|
|
118
123
|
QueryTypes,
|
|
119
124
|
ResponseTypes,
|
|
120
|
-
|
|
125
|
+
Registration,
|
|
121
126
|
EventItems,
|
|
122
127
|
makeWithAgent,
|
|
123
128
|
logLevelSchema,
|
|
@@ -35,8 +35,7 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (u
|
|
|
35
35
|
and scheduleReconnect = () => {
|
|
36
36
|
// Clear any pending stale/reconnect timeout to avoid double reconnect
|
|
37
37
|
timeoutIdRef.contents->clearTimeout
|
|
38
|
-
let delay =
|
|
39
|
-
baseDuration * Math.pow(2.0, ~exp=errorCount.contents->Int.toFloat)->Float.toInt
|
|
38
|
+
let delay = baseDuration * Math.pow(2.0, ~exp=errorCount.contents->Int.toFloat)->Float.toInt
|
|
40
39
|
timeoutIdRef := setTimeout(() => refreshEventSource(), Pervasives.min(delay, 60_000))
|
|
41
40
|
}
|
|
42
41
|
and refreshEventSource = () => {
|
|
@@ -102,12 +101,6 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (u
|
|
|
102
101
|
es->EventSource.addEventListener("height", event => {
|
|
103
102
|
switch event.data->Int.fromString {
|
|
104
103
|
| Some(height) =>
|
|
105
|
-
// Track the SSE height event
|
|
106
|
-
Prometheus.SourceRequestCount.increment(
|
|
107
|
-
~sourceName="HyperSync",
|
|
108
|
-
~chainId,
|
|
109
|
-
~method="heightStream",
|
|
110
|
-
)
|
|
111
104
|
// On a successful height event, update the timeout
|
|
112
105
|
updateTimeoutId()
|
|
113
106
|
// Call the callback with the new height
|