envio 3.3.0-alpha.1 → 3.3.0-alpha.10
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/package.json +7 -7
- 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 +43 -9
- package/src/ChainFetching.res.mjs +34 -15
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +605 -151
- package/src/ChainState.res.mjs +427 -104
- package/src/ChainState.resi +72 -4
- package/src/Config.res +61 -33
- package/src/Config.res.mjs +50 -10
- package/src/ContractRegisterContext.res +2 -12
- package/src/ContractRegisterContext.res.mjs +3 -5
- package/src/Core.res +14 -3
- package/src/CrossChainState.res +113 -89
- package/src/CrossChainState.res.mjs +64 -60
- 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 +177 -88
- package/src/EventConfigBuilder.res.mjs +99 -42
- package/src/EventProcessing.res +74 -28
- package/src/EventProcessing.res.mjs +55 -29
- package/src/ExitOnCaughtUp.res +10 -2
- package/src/ExitOnCaughtUp.res.mjs +10 -1
- package/src/FetchState.res +544 -356
- package/src/FetchState.res.mjs +412 -471
- package/src/HandlerLoader.res +8 -104
- package/src/HandlerLoader.res.mjs +2 -81
- package/src/HandlerRegister.res +518 -144
- package/src/HandlerRegister.res.mjs +285 -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 +155 -46
- package/src/Internal.res.mjs +30 -2
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/LogSelection.res +102 -165
- package/src/LogSelection.res.mjs +101 -116
- 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 +91 -23
- package/src/SimulateItems.res.mjs +55 -32
- package/src/TestIndexer.res +54 -40
- package/src/TestIndexer.res.mjs +37 -30
- 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 -41
- 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 +36 -33
- package/src/sources/EventRouter.res.mjs +13 -14
- package/src/sources/Evm.res +83 -72
- package/src/sources/Evm.res.mjs +53 -69
- package/src/sources/EvmChain.res +18 -20
- package/src/sources/EvmChain.res.mjs +15 -15
- package/src/sources/EvmRpcClient.res +74 -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 +39 -7
- package/src/sources/HyperSync.res.mjs +57 -37
- package/src/sources/HyperSync.resi +12 -2
- package/src/sources/HyperSyncClient.res +22 -111
- package/src/sources/HyperSyncClient.res.mjs +2 -30
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +94 -107
- package/src/sources/HyperSyncSource.res.mjs +82 -86
- package/src/sources/Rpc.res +15 -47
- package/src/sources/Rpc.res.mjs +25 -56
- package/src/sources/RpcSource.res +320 -467
- package/src/sources/RpcSource.res.mjs +268 -385
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +10 -4
- package/src/sources/SimulateSource.res.mjs +16 -6
- 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
|
@@ -16,9 +16,15 @@ let reraisIfRateLimited = exn =>
|
|
|
16
16
|
|
|
17
17
|
type logsQueryPage = {
|
|
18
18
|
items: array<HyperSyncClient.EventItems.item>,
|
|
19
|
+
// Block headers referenced by `items`, deduplicated by block number.
|
|
20
|
+
blocks: array<HyperSyncClient.EventItems.blockHeader>,
|
|
19
21
|
nextBlock: int,
|
|
20
22
|
archiveHeight: int,
|
|
21
23
|
rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
|
|
24
|
+
// Page store owning this page's raw transactions.
|
|
25
|
+
transactionStore: TransactionStore.t,
|
|
26
|
+
// Page store owning this page's raw blocks.
|
|
27
|
+
blockStore: BlockStore.t,
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
type missingParams = {
|
|
@@ -60,6 +66,7 @@ module GetLogs = {
|
|
|
60
66
|
~toBlockInclusive,
|
|
61
67
|
~addressesWithTopics,
|
|
62
68
|
~fieldSelection,
|
|
69
|
+
~maxNumLogs,
|
|
63
70
|
): HyperSyncClient.QueryTypes.query => {
|
|
64
71
|
fromBlock,
|
|
65
72
|
toBlockExclusive: ?switch toBlockInclusive {
|
|
@@ -68,6 +75,7 @@ module GetLogs = {
|
|
|
68
75
|
},
|
|
69
76
|
logs: addressesWithTopics,
|
|
70
77
|
fieldSelection,
|
|
78
|
+
maxNumLogs,
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
// Rust encodes structured failures as a JSON payload in the napi error's
|
|
@@ -101,6 +109,7 @@ module GetLogs = {
|
|
|
101
109
|
~toBlock,
|
|
102
110
|
~logSelections: array<LogSelection.t>,
|
|
103
111
|
~fieldSelection,
|
|
112
|
+
~maxNumLogs,
|
|
104
113
|
): logsQueryPage => {
|
|
105
114
|
let addressesWithTopics = logSelections->Array.flatMap(({addresses, topicSelections}) =>
|
|
106
115
|
topicSelections->Array.map(({topic0, topic1, topic2, topic3}) => {
|
|
@@ -119,9 +128,10 @@ module GetLogs = {
|
|
|
119
128
|
~toBlockInclusive=toBlock,
|
|
120
129
|
~addressesWithTopics,
|
|
121
130
|
~fieldSelection,
|
|
131
|
+
~maxNumLogs,
|
|
122
132
|
)
|
|
123
133
|
|
|
124
|
-
let res = switch await client.getEventItems(~query) {
|
|
134
|
+
let (res, transactionStore, blockStore) = switch await client.getEventItems(~query) {
|
|
125
135
|
| res => res
|
|
126
136
|
| exception exn =>
|
|
127
137
|
reraisIfRateLimited(exn)
|
|
@@ -137,9 +147,12 @@ module GetLogs = {
|
|
|
137
147
|
|
|
138
148
|
{
|
|
139
149
|
items: res.items,
|
|
150
|
+
blocks: res.blocks,
|
|
140
151
|
nextBlock: res.nextBlock,
|
|
141
152
|
archiveHeight: res.archiveHeight->Option.getOr(0), //Archive Height is only None if height is 0
|
|
142
153
|
rollbackGuard: res.rollbackGuard,
|
|
154
|
+
transactionStore,
|
|
155
|
+
blockStore,
|
|
143
156
|
}
|
|
144
157
|
}
|
|
145
158
|
}
|
|
@@ -196,6 +209,7 @@ module BlockData = {
|
|
|
196
209
|
~sourceName,
|
|
197
210
|
~chainId,
|
|
198
211
|
~logger,
|
|
212
|
+
~requestStats: array<Source.requestStat>,
|
|
199
213
|
): queryResponse<array<ReorgDetection.blockDataWithTimestamp>> => {
|
|
200
214
|
let body = makeRequestBody(~fromBlock, ~toBlock)
|
|
201
215
|
|
|
@@ -208,7 +222,7 @@ module BlockData = {
|
|
|
208
222
|
},
|
|
209
223
|
)
|
|
210
224
|
|
|
211
|
-
|
|
225
|
+
let timerRef = Performance.now()
|
|
212
226
|
let maybeSuccessfulRes = switch await client.get(~query=body) {
|
|
213
227
|
| exception exn =>
|
|
214
228
|
reraisIfRateLimited(exn)
|
|
@@ -216,6 +230,9 @@ module BlockData = {
|
|
|
216
230
|
| res if res.nextBlock <= fromBlock => None
|
|
217
231
|
| res => Some(res)
|
|
218
232
|
}
|
|
233
|
+
requestStats
|
|
234
|
+
->Array.push({Source.method: "getBlockHashes", seconds: timerRef->Performance.secondsSince})
|
|
235
|
+
->ignore
|
|
219
236
|
|
|
220
237
|
// If the block is not found, retry the query. This can occur since replicas of hypersync might not have caught up yet
|
|
221
238
|
switch maybeSuccessfulRes {
|
|
@@ -225,7 +242,15 @@ module BlockData = {
|
|
|
225
242
|
`Block #${fromBlock->Int.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 ${delayMilliseconds->Int.toString}ms.`,
|
|
226
243
|
)
|
|
227
244
|
await Time.resolvePromiseAfterDelay(~delayMilliseconds)
|
|
228
|
-
await queryBlockData(
|
|
245
|
+
await queryBlockData(
|
|
246
|
+
~client,
|
|
247
|
+
~fromBlock,
|
|
248
|
+
~toBlock,
|
|
249
|
+
~sourceName,
|
|
250
|
+
~chainId,
|
|
251
|
+
~logger,
|
|
252
|
+
~requestStats,
|
|
253
|
+
)
|
|
229
254
|
}
|
|
230
255
|
| Some(res) =>
|
|
231
256
|
switch res->convertResponse {
|
|
@@ -238,6 +263,7 @@ module BlockData = {
|
|
|
238
263
|
~sourceName,
|
|
239
264
|
~chainId,
|
|
240
265
|
~logger,
|
|
266
|
+
~requestStats,
|
|
241
267
|
)
|
|
242
268
|
restRes->Result.map(rest => datas->Array.concat(rest))
|
|
243
269
|
}
|
|
@@ -252,8 +278,9 @@ module BlockData = {
|
|
|
252
278
|
~sourceName,
|
|
253
279
|
~chainId,
|
|
254
280
|
~logger,
|
|
255
|
-
) => {
|
|
256
|
-
|
|
281
|
+
): (queryResponse<array<ReorgDetection.blockDataWithTimestamp>>, array<Source.requestStat>) => {
|
|
282
|
+
let requestStats = []
|
|
283
|
+
let result = switch blockNumbers->Array.get(0) {
|
|
257
284
|
| None => Ok([])
|
|
258
285
|
| Some(firstBlock) => {
|
|
259
286
|
let fromBlock = ref(firstBlock)
|
|
@@ -281,6 +308,7 @@ module BlockData = {
|
|
|
281
308
|
~sourceName,
|
|
282
309
|
~chainId,
|
|
283
310
|
~logger,
|
|
311
|
+
~requestStats,
|
|
284
312
|
)
|
|
285
313
|
let filtered = res->Result.map(datas => {
|
|
286
314
|
datas->Array.filter(data => set->Utils.Set.delete(data.blockNumber))
|
|
@@ -295,10 +323,12 @@ module BlockData = {
|
|
|
295
323
|
filtered
|
|
296
324
|
}
|
|
297
325
|
}
|
|
326
|
+
(result, requestStats)
|
|
298
327
|
}
|
|
299
328
|
}
|
|
300
329
|
|
|
301
|
-
let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
|
|
330
|
+
let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) => {
|
|
331
|
+
let requestStats = []
|
|
302
332
|
BlockData.queryBlockData(
|
|
303
333
|
~client,
|
|
304
334
|
~fromBlock=blockNumber,
|
|
@@ -306,5 +336,7 @@ let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
|
|
|
306
336
|
~sourceName,
|
|
307
337
|
~chainId,
|
|
308
338
|
~logger,
|
|
309
|
-
|
|
339
|
+
~requestStats,
|
|
340
|
+
)->Promise.thenResolve(res => (res->Result.map(res => res->Array.get(0)), requestStats))
|
|
341
|
+
}
|
|
310
342
|
let queryBlockDataMulti = BlockData.queryBlockDataMulti
|
|
@@ -4,8 +4,8 @@ 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";
|
|
@@ -62,12 +62,13 @@ function mapExn(queryResponse) {
|
|
|
62
62
|
|
|
63
63
|
let $$Error = /* @__PURE__ */Primitive_exceptions.create("HyperSync.GetLogs.Error");
|
|
64
64
|
|
|
65
|
-
function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, fieldSelection) {
|
|
65
|
+
function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, fieldSelection, maxNumLogs) {
|
|
66
66
|
return {
|
|
67
67
|
fromBlock: fromBlock,
|
|
68
68
|
toBlock: toBlockInclusive !== undefined ? toBlockInclusive + 1 | 0 : undefined,
|
|
69
69
|
logs: addressesWithTopics,
|
|
70
|
-
fieldSelection: fieldSelection
|
|
70
|
+
fieldSelection: fieldSelection,
|
|
71
|
+
maxNumLogs: maxNumLogs
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
|
|
@@ -92,7 +93,7 @@ function extractMissingParams(exn) {
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
async function query(client, fromBlock, toBlock, logSelections, fieldSelection) {
|
|
96
|
+
async function query(client, fromBlock, toBlock, logSelections, fieldSelection, maxNumLogs) {
|
|
96
97
|
let addressesWithTopics = logSelections.flatMap(param => {
|
|
97
98
|
let addresses = param.addresses;
|
|
98
99
|
return param.topicSelections.map(param => {
|
|
@@ -100,10 +101,10 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
|
|
|
100
101
|
return HyperSyncClient.QueryTypes.makeLogSelection(addresses, topics);
|
|
101
102
|
});
|
|
102
103
|
});
|
|
103
|
-
let query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection);
|
|
104
|
-
let
|
|
104
|
+
let query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection, maxNumLogs);
|
|
105
|
+
let match;
|
|
105
106
|
try {
|
|
106
|
-
|
|
107
|
+
match = await client.getEventItems(query$1);
|
|
107
108
|
} catch (raw_exn) {
|
|
108
109
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
109
110
|
reraisIfRateLimited(exn);
|
|
@@ -120,6 +121,7 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
|
|
|
120
121
|
}
|
|
121
122
|
throw exn;
|
|
122
123
|
}
|
|
124
|
+
let res = match[0];
|
|
123
125
|
if (res.nextBlock <= fromBlock) {
|
|
124
126
|
throw {
|
|
125
127
|
RE_EXN_ID: $$Error,
|
|
@@ -129,9 +131,12 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
|
|
|
129
131
|
}
|
|
130
132
|
return {
|
|
131
133
|
items: res.items,
|
|
134
|
+
blocks: res.blocks,
|
|
132
135
|
nextBlock: res.nextBlock,
|
|
133
136
|
archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
|
|
134
|
-
rollbackGuard: res.rollbackGuard
|
|
137
|
+
rollbackGuard: res.rollbackGuard,
|
|
138
|
+
transactionStore: match[1],
|
|
139
|
+
blockStore: match[2]
|
|
135
140
|
};
|
|
136
141
|
}
|
|
137
142
|
|
|
@@ -187,14 +192,14 @@ function convertResponse(res) {
|
|
|
187
192
|
}));
|
|
188
193
|
}
|
|
189
194
|
|
|
190
|
-
async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger) {
|
|
195
|
+
async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats) {
|
|
191
196
|
let body = makeRequestBody$1(fromBlock, toBlock);
|
|
192
197
|
let logger$1 = Logging.createChildFrom(logger, {
|
|
193
198
|
logType: "HyperSync get block hash query",
|
|
194
199
|
fromBlock: fromBlock,
|
|
195
200
|
toBlock: toBlock
|
|
196
201
|
});
|
|
197
|
-
|
|
202
|
+
let timerRef = Performance.now();
|
|
198
203
|
let maybeSuccessfulRes;
|
|
199
204
|
let exit = 0;
|
|
200
205
|
let res;
|
|
@@ -209,6 +214,10 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
|
|
|
209
214
|
if (exit === 1) {
|
|
210
215
|
maybeSuccessfulRes = res.nextBlock <= fromBlock ? undefined : res;
|
|
211
216
|
}
|
|
217
|
+
requestStats.push({
|
|
218
|
+
method: "getBlockHashes",
|
|
219
|
+
seconds: Performance.secondsSince(timerRef)
|
|
220
|
+
});
|
|
212
221
|
if (maybeSuccessfulRes !== undefined) {
|
|
213
222
|
let err = convertResponse(maybeSuccessfulRes);
|
|
214
223
|
if (err.TAG !== "Ok") {
|
|
@@ -218,48 +227,59 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
|
|
|
218
227
|
return err;
|
|
219
228
|
}
|
|
220
229
|
let datas = err._0;
|
|
221
|
-
let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1);
|
|
230
|
+
let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1, requestStats);
|
|
222
231
|
return Stdlib_Result.map(restRes, rest => datas.concat(rest));
|
|
223
232
|
}
|
|
224
233
|
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
234
|
await Time.resolvePromiseAfterDelay(100);
|
|
226
|
-
return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1);
|
|
235
|
+
return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1, requestStats);
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
async function queryBlockDataMulti(client, blockNumbers, sourceName, chainId, logger) {
|
|
239
|
+
let requestStats = [];
|
|
230
240
|
let firstBlock = blockNumbers[0];
|
|
231
|
-
|
|
232
|
-
|
|
241
|
+
let result;
|
|
242
|
+
if (firstBlock !== undefined) {
|
|
243
|
+
let fromBlock = firstBlock;
|
|
244
|
+
let toBlock = firstBlock;
|
|
245
|
+
let set = new Set();
|
|
246
|
+
for (let idx = 0, idx_finish = blockNumbers.length; idx < idx_finish; ++idx) {
|
|
247
|
+
let blockNumber = blockNumbers[idx];
|
|
248
|
+
if (blockNumber < fromBlock) {
|
|
249
|
+
fromBlock = blockNumber;
|
|
250
|
+
}
|
|
251
|
+
if (blockNumber > toBlock) {
|
|
252
|
+
toBlock = blockNumber;
|
|
253
|
+
}
|
|
254
|
+
set.add(blockNumber);
|
|
255
|
+
}
|
|
256
|
+
if ((toBlock - fromBlock | 0) > 1000) {
|
|
257
|
+
Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
|
|
258
|
+
}
|
|
259
|
+
let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats);
|
|
260
|
+
let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
|
|
261
|
+
if (set.size > 0) {
|
|
262
|
+
Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
|
|
263
|
+
}
|
|
264
|
+
result = filtered;
|
|
265
|
+
} else {
|
|
266
|
+
result = {
|
|
233
267
|
TAG: "Ok",
|
|
234
268
|
_0: []
|
|
235
269
|
};
|
|
236
270
|
}
|
|
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;
|
|
271
|
+
return [
|
|
272
|
+
result,
|
|
273
|
+
requestStats
|
|
274
|
+
];
|
|
259
275
|
}
|
|
260
276
|
|
|
261
277
|
function queryBlockData$1(client, blockNumber, sourceName, chainId, logger) {
|
|
262
|
-
|
|
278
|
+
let requestStats = [];
|
|
279
|
+
return queryBlockData(client, blockNumber, blockNumber, sourceName, chainId, logger, requestStats).then(res => [
|
|
280
|
+
Stdlib_Result.map(res, res => res[0]),
|
|
281
|
+
requestStats
|
|
282
|
+
]);
|
|
263
283
|
}
|
|
264
284
|
|
|
265
285
|
let 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 = {
|
|
@@ -31,6 +34,7 @@ module GetLogs: {
|
|
|
31
34
|
~toBlock: option<int>,
|
|
32
35
|
~logSelections: array<LogSelection.t>,
|
|
33
36
|
~fieldSelection: HyperSyncClient.QueryTypes.fieldSelection,
|
|
37
|
+
~maxNumLogs: int,
|
|
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>,
|
|
@@ -325,25 +237,6 @@ module Decoder = {
|
|
|
325
237
|
contractName: string,
|
|
326
238
|
params: array<Internal.paramMeta>,
|
|
327
239
|
}
|
|
328
|
-
|
|
329
|
-
// Decoded params keyed by contract name. Contracts that emit the same-signature
|
|
330
|
-
// event share one decode but get their own param names, so the caller picks the
|
|
331
|
-
// entry for the contract its router resolved the log to.
|
|
332
|
-
type tWithParams = {
|
|
333
|
-
decodeLogs: array<ResponseTypes.event> => promise<
|
|
334
|
-
array<Nullable.t<dict<Internal.eventParams>>>,
|
|
335
|
-
>,
|
|
336
|
-
}
|
|
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
240
|
}
|
|
348
241
|
|
|
349
242
|
module EventItems = {
|
|
@@ -352,14 +245,28 @@ module EventItems = {
|
|
|
352
245
|
srcAddress: Address.t,
|
|
353
246
|
topic0: EvmTypes.Hex.t,
|
|
354
247
|
topicCount: int,
|
|
355
|
-
block
|
|
356
|
-
|
|
248
|
+
// Number of the block this log belongs to; the block itself is resolved from
|
|
249
|
+
// `response.blocks`, deduplicated across items sharing a block.
|
|
250
|
+
blockNumber: int,
|
|
251
|
+
// Key (with the block number) into the transaction store; the transaction
|
|
252
|
+
// is resolved from the store on demand.
|
|
253
|
+
transactionIndex: int,
|
|
357
254
|
params: Nullable.t<dict<Internal.eventParams>>,
|
|
358
255
|
}
|
|
359
256
|
|
|
257
|
+
// The always-needed block fields, one per block number. The block's remaining
|
|
258
|
+
// fields live raw in the block store and are materialised on demand.
|
|
259
|
+
type blockHeader = {
|
|
260
|
+
number: int,
|
|
261
|
+
timestamp: int,
|
|
262
|
+
hash: string,
|
|
263
|
+
}
|
|
264
|
+
|
|
360
265
|
type response = {
|
|
361
266
|
archiveHeight: option<int>,
|
|
362
267
|
nextBlock: int,
|
|
268
|
+
// One header per block number referenced by `items`.
|
|
269
|
+
blocks: array<blockHeader>,
|
|
363
270
|
items: array<item>,
|
|
364
271
|
rollbackGuard: option<ResponseTypes.rollbackGuard>,
|
|
365
272
|
}
|
|
@@ -367,7 +274,11 @@ module EventItems = {
|
|
|
367
274
|
|
|
368
275
|
type t = {
|
|
369
276
|
get: (~query: query) => promise<queryResponse>,
|
|
370
|
-
|
|
277
|
+
// Returns the response plus page stores owning this page's raw transactions
|
|
278
|
+
// and blocks.
|
|
279
|
+
getEventItems: (
|
|
280
|
+
~query: query,
|
|
281
|
+
) => promise<(EventItems.response, TransactionStore.t, BlockStore.t)>,
|
|
371
282
|
getHeight: unit => promise<int>,
|
|
372
283
|
}
|
|
373
284
|
|
|
@@ -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,35 +34,9 @@ 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
|
-
let
|
|
45
|
-
chainId: s.f("chainId", S$RescriptSchema.bigint),
|
|
46
|
-
address: s.f("address", Address.schema),
|
|
47
|
-
nonce: s.f("nonce", S$RescriptSchema.int),
|
|
48
|
-
yParity: s.f("yParity", S$RescriptSchema.$$enum([
|
|
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
|
-
};
|
|
60
|
-
|
|
61
|
-
function fromParams(eventParams, checksumAddresses) {
|
|
62
|
-
return Core.getAddon().EvmDecoder.fromParams(eventParams, checksumAddresses !== undefined ? Primitive_option.valFromOption(checksumAddresses) : undefined);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
let Decoder = {
|
|
66
|
-
fromParams: fromParams
|
|
67
|
-
};
|
|
39
|
+
let Decoder = {};
|
|
68
40
|
|
|
69
41
|
let EventItems = {};
|
|
70
42
|
|
|
@@ -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
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Utils from "../Utils.res.mjs";
|
|
4
4
|
import * as Logging from "../Logging.res.mjs";
|
|
5
|
-
import * as Prometheus from "../Prometheus.res.mjs";
|
|
6
5
|
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
7
6
|
import * as Eventsource from "eventsource";
|
|
8
7
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
@@ -83,7 +82,6 @@ function subscribe(hyperSyncUrl, apiToken, chainId, onHeight) {
|
|
|
83
82
|
es$1.addEventListener("height", event => {
|
|
84
83
|
let height = Stdlib_Int.fromString(event.data, undefined);
|
|
85
84
|
if (height !== undefined) {
|
|
86
|
-
Prometheus.SourceRequestCount.increment("HyperSync", chainId, "heightStream");
|
|
87
85
|
updateTimeoutId();
|
|
88
86
|
return onHeight(height);
|
|
89
87
|
} else {
|