envio 3.0.0-alpha.11 → 3.0.0-alpha.12
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 +18 -0
- package/package.json +5 -5
- package/src/Batch.res +2 -0
- package/src/Batch.res.mjs +1 -0
- package/src/Config.res +7 -1
- package/src/Config.res.mjs +6 -3
- package/src/GlobalState.res +0 -1
- package/src/GlobalState.res.mjs +0 -1
- package/src/PgStorage.res +1 -0
- package/src/PgStorage.res.mjs +1 -0
- package/src/db/InternalTable.res +5 -3
- package/src/db/InternalTable.res.mjs +6 -4
- package/src/sources/EvmChain.res +3 -0
- package/src/sources/EvmChain.res.mjs +2 -1
- package/src/sources/Rpc.res +21 -21
- package/src/sources/Rpc.res.mjs +18 -18
- package/src/sources/RpcSource.res +37 -38
- package/src/sources/RpcSource.res.mjs +42 -36
package/evm.schema.json
CHANGED
|
@@ -458,6 +458,15 @@
|
|
|
458
458
|
],
|
|
459
459
|
"format": "uint32",
|
|
460
460
|
"minimum": 0
|
|
461
|
+
},
|
|
462
|
+
"polling_interval": {
|
|
463
|
+
"description": "How frequently (in milliseconds) to check for new blocks in realtime. Default is 1000ms. Note: Setting this higher than block time does not reduce RPC usage as every block is still fetched to check for reorgs.",
|
|
464
|
+
"type": [
|
|
465
|
+
"integer",
|
|
466
|
+
"null"
|
|
467
|
+
],
|
|
468
|
+
"format": "uint32",
|
|
469
|
+
"minimum": 0
|
|
461
470
|
}
|
|
462
471
|
},
|
|
463
472
|
"additionalProperties": false,
|
|
@@ -553,6 +562,15 @@
|
|
|
553
562
|
],
|
|
554
563
|
"format": "uint32",
|
|
555
564
|
"minimum": 0
|
|
565
|
+
},
|
|
566
|
+
"polling_interval": {
|
|
567
|
+
"description": "How frequently (in milliseconds) to check for new blocks in realtime. Default is 1000ms. Note: Setting this higher than block time does not reduce RPC usage as every block is still fetched to check for reorgs.",
|
|
568
|
+
"type": [
|
|
569
|
+
"integer",
|
|
570
|
+
"null"
|
|
571
|
+
],
|
|
572
|
+
"format": "uint32",
|
|
573
|
+
"minimum": 0
|
|
556
574
|
}
|
|
557
575
|
},
|
|
558
576
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "v3.0.0-alpha.
|
|
3
|
+
"version": "v3.0.0-alpha.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
|
|
6
6
|
"bin": "./bin.js",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"node": ">=22.0.0"
|
|
30
30
|
},
|
|
31
31
|
"optionalDependencies": {
|
|
32
|
-
"envio-linux-x64": "v3.0.0-alpha.
|
|
33
|
-
"envio-linux-arm64": "v3.0.0-alpha.
|
|
34
|
-
"envio-darwin-x64": "v3.0.0-alpha.
|
|
35
|
-
"envio-darwin-arm64": "v3.0.0-alpha.
|
|
32
|
+
"envio-linux-x64": "v3.0.0-alpha.12",
|
|
33
|
+
"envio-linux-arm64": "v3.0.0-alpha.12",
|
|
34
|
+
"envio-darwin-x64": "v3.0.0-alpha.12",
|
|
35
|
+
"envio-darwin-arm64": "v3.0.0-alpha.12"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@clickhouse/client": "1.12.1",
|
package/src/Batch.res
CHANGED
|
@@ -6,6 +6,7 @@ open Utils.UnsafeIntOperators
|
|
|
6
6
|
type chainAfterBatch = {
|
|
7
7
|
batchSize: int,
|
|
8
8
|
progressBlockNumber: int,
|
|
9
|
+
sourceBlockNumber: int,
|
|
9
10
|
totalEventsProcessed: int,
|
|
10
11
|
fetchState: FetchState.t,
|
|
11
12
|
isProgressAtHeadWhenBatchCreated: bool,
|
|
@@ -108,6 +109,7 @@ let getProgressedChainsById = {
|
|
|
108
109
|
{
|
|
109
110
|
batchSize,
|
|
110
111
|
progressBlockNumber: progressBlockNumberAfterBatch,
|
|
112
|
+
sourceBlockNumber: chainBeforeBatch.sourceBlockNumber,
|
|
111
113
|
totalEventsProcessed: chainBeforeBatch.totalEventsProcessed + batchSize,
|
|
112
114
|
fetchState: fetchStateAfterBatch,
|
|
113
115
|
isProgressAtHeadWhenBatchCreated: progressBlockNumberAfterBatch >=
|
package/src/Batch.res.mjs
CHANGED
|
@@ -62,6 +62,7 @@ function getChainAfterBatchIfProgressed(chainBeforeBatch, progressBlockNumberAft
|
|
|
62
62
|
return {
|
|
63
63
|
batchSize: batchSize,
|
|
64
64
|
progressBlockNumber: progressBlockNumberAfterBatch,
|
|
65
|
+
sourceBlockNumber: chainBeforeBatch.sourceBlockNumber,
|
|
65
66
|
totalEventsProcessed: chainBeforeBatch.totalEventsProcessed + batchSize,
|
|
66
67
|
fetchState: fetchStateAfterBatch,
|
|
67
68
|
isProgressAtHeadWhenBatchCreated: progressBlockNumberAfterBatch >= chainBeforeBatch.sourceBlockNumber
|
package/src/Config.res
CHANGED
|
@@ -8,6 +8,7 @@ type sourceSyncOptions = {
|
|
|
8
8
|
backoffMillis?: int,
|
|
9
9
|
queryTimeoutMillis?: int,
|
|
10
10
|
fallbackStallTimeout?: int,
|
|
11
|
+
pollingInterval?: int,
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
type contract = {
|
|
@@ -65,6 +66,7 @@ type sourceSync = {
|
|
|
65
66
|
backoffMillis: int,
|
|
66
67
|
queryTimeoutMillis: int,
|
|
67
68
|
fallbackStallTimeout: int,
|
|
69
|
+
pollingInterval: int,
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
type multichain = | @as("ordered") Ordered | @as("unordered") Unordered
|
|
@@ -109,6 +111,7 @@ let rpcConfigSchema = S.schema(s =>
|
|
|
109
111
|
"backoffMillis": s.matches(S.option(S.int)),
|
|
110
112
|
"fallbackStallTimeout": s.matches(S.option(S.int)),
|
|
111
113
|
"queryTimeoutMillis": s.matches(S.option(S.int)),
|
|
114
|
+
"pollingInterval": s.matches(S.option(S.int)),
|
|
112
115
|
}
|
|
113
116
|
)
|
|
114
117
|
|
|
@@ -323,6 +326,7 @@ let fromPublic = (
|
|
|
323
326
|
let backoffMillis = rpcConfig["backoffMillis"]
|
|
324
327
|
let queryTimeoutMillis = rpcConfig["queryTimeoutMillis"]
|
|
325
328
|
let fallbackStallTimeout = rpcConfig["fallbackStallTimeout"]
|
|
329
|
+
let pollingInterval = rpcConfig["pollingInterval"]
|
|
326
330
|
let hasSyncConfig =
|
|
327
331
|
initialBlockInterval->Option.isSome ||
|
|
328
332
|
backoffMultiplicative->Option.isSome ||
|
|
@@ -330,7 +334,8 @@ let fromPublic = (
|
|
|
330
334
|
intervalCeiling->Option.isSome ||
|
|
331
335
|
backoffMillis->Option.isSome ||
|
|
332
336
|
queryTimeoutMillis->Option.isSome ||
|
|
333
|
-
fallbackStallTimeout->Option.isSome
|
|
337
|
+
fallbackStallTimeout->Option.isSome ||
|
|
338
|
+
pollingInterval->Option.isSome
|
|
334
339
|
let syncConfig: option<sourceSyncOptions> = if hasSyncConfig {
|
|
335
340
|
Some({
|
|
336
341
|
?initialBlockInterval,
|
|
@@ -340,6 +345,7 @@ let fromPublic = (
|
|
|
340
345
|
?backoffMillis,
|
|
341
346
|
?queryTimeoutMillis,
|
|
342
347
|
?fallbackStallTimeout,
|
|
348
|
+
?pollingInterval,
|
|
343
349
|
})
|
|
344
350
|
} else {
|
|
345
351
|
None
|
package/src/Config.res.mjs
CHANGED
|
@@ -30,7 +30,8 @@ var rpcConfigSchema = S$RescriptSchema.schema(function (s) {
|
|
|
30
30
|
intervalCeiling: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
|
|
31
31
|
backoffMillis: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
|
|
32
32
|
fallbackStallTimeout: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
|
|
33
|
-
queryTimeoutMillis: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int))
|
|
33
|
+
queryTimeoutMillis: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
|
|
34
|
+
pollingInterval: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int))
|
|
34
35
|
};
|
|
35
36
|
});
|
|
36
37
|
|
|
@@ -235,7 +236,8 @@ function fromPublic(publicConfigJson, codegenChainsOpt, maxAddrInPartitionOpt, u
|
|
|
235
236
|
var backoffMillis = rpcConfig.backoffMillis;
|
|
236
237
|
var queryTimeoutMillis = rpcConfig.queryTimeoutMillis;
|
|
237
238
|
var fallbackStallTimeout = rpcConfig.fallbackStallTimeout;
|
|
238
|
-
var
|
|
239
|
+
var pollingInterval = rpcConfig.pollingInterval;
|
|
240
|
+
var hasSyncConfig = Belt_Option.isSome(initialBlockInterval) || Belt_Option.isSome(backoffMultiplicative) || Belt_Option.isSome(accelerationAdditive) || Belt_Option.isSome(intervalCeiling) || Belt_Option.isSome(backoffMillis) || Belt_Option.isSome(queryTimeoutMillis) || Belt_Option.isSome(fallbackStallTimeout) || Belt_Option.isSome(pollingInterval);
|
|
239
241
|
var syncConfig = hasSyncConfig ? ({
|
|
240
242
|
initialBlockInterval: initialBlockInterval,
|
|
241
243
|
backoffMultiplicative: backoffMultiplicative,
|
|
@@ -243,7 +245,8 @@ function fromPublic(publicConfigJson, codegenChainsOpt, maxAddrInPartitionOpt, u
|
|
|
243
245
|
intervalCeiling: intervalCeiling,
|
|
244
246
|
backoffMillis: backoffMillis,
|
|
245
247
|
queryTimeoutMillis: queryTimeoutMillis,
|
|
246
|
-
fallbackStallTimeout: fallbackStallTimeout
|
|
248
|
+
fallbackStallTimeout: fallbackStallTimeout,
|
|
249
|
+
pollingInterval: pollingInterval
|
|
247
250
|
}) : undefined;
|
|
248
251
|
return {
|
|
249
252
|
url: rpcConfig.url,
|
package/src/GlobalState.res
CHANGED
|
@@ -159,7 +159,6 @@ let updateChainMetadataTable = (
|
|
|
159
159
|
chainsData->Js.Dict.set(
|
|
160
160
|
cf.chainConfig.id->Belt.Int.toString,
|
|
161
161
|
{
|
|
162
|
-
blockHeight: cf.fetchState.knownHeight,
|
|
163
162
|
firstEventBlockNumber: cf.firstEventBlockNumber->Js.Null.fromOption,
|
|
164
163
|
isHyperSync: (cf.sourceManager->SourceManager.getActiveSource).poweredByHyperSync,
|
|
165
164
|
latestFetchedBlockNumber: cf.fetchState->FetchState.bufferBlockNumber,
|
package/src/GlobalState.res.mjs
CHANGED
|
@@ -127,7 +127,6 @@ function updateChainMetadataTable(cm, persistence, throttler) {
|
|
|
127
127
|
chainsData[String(cf.chainConfig.id)] = {
|
|
128
128
|
first_event_block: Js_null.fromOption(cf.firstEventBlockNumber),
|
|
129
129
|
buffer_block: FetchState.bufferBlockNumber(cf.fetchState),
|
|
130
|
-
source_block: cf.fetchState.knownHeight,
|
|
131
130
|
ready_at: Js_null.fromOption(cf.timestampCaughtUpToHeadOrEndblock),
|
|
132
131
|
_is_hyper_sync: SourceManager.getActiveSource(cf.sourceManager).poweredByHyperSync,
|
|
133
132
|
_num_batches_fetched: cf.numBatchesFetched
|
package/src/PgStorage.res
CHANGED
|
@@ -933,6 +933,7 @@ let rec writeBatch = async (
|
|
|
933
933
|
): InternalTable.Chains.progressedChain => {
|
|
934
934
|
chainId: chainAfterBatch.fetchState.chainId,
|
|
935
935
|
progressBlockNumber: chainAfterBatch.progressBlockNumber,
|
|
936
|
+
sourceBlockNumber: chainAfterBatch.sourceBlockNumber,
|
|
936
937
|
totalEventsProcessed: chainAfterBatch.totalEventsProcessed,
|
|
937
938
|
}),
|
|
938
939
|
),
|
package/src/PgStorage.res.mjs
CHANGED
|
@@ -635,6 +635,7 @@ async function writeBatch(sql, batch, rawEvents, pgSchema, rollbackTargetCheckpo
|
|
|
635
635
|
return {
|
|
636
636
|
chainId: chainAfterBatch.fetchState.chainId,
|
|
637
637
|
progressBlockNumber: chainAfterBatch.progressBlockNumber,
|
|
638
|
+
sourceBlockNumber: chainAfterBatch.sourceBlockNumber,
|
|
638
639
|
totalEventsProcessed: chainAfterBatch.totalEventsProcessed
|
|
639
640
|
};
|
|
640
641
|
})));
|
package/src/db/InternalTable.res
CHANGED
|
@@ -74,6 +74,7 @@ module Chains = {
|
|
|
74
74
|
type progressFields = [
|
|
75
75
|
| #progress_block
|
|
76
76
|
| #events_processed
|
|
77
|
+
| #source_block
|
|
77
78
|
]
|
|
78
79
|
|
|
79
80
|
type field = [
|
|
@@ -108,7 +109,6 @@ module Chains = {
|
|
|
108
109
|
type metaFields = {
|
|
109
110
|
@as("first_event_block") firstEventBlockNumber: Js.null<int>,
|
|
110
111
|
@as("buffer_block") latestFetchedBlockNumber: int,
|
|
111
|
-
@as("source_block") blockHeight: int,
|
|
112
112
|
@as("ready_at")
|
|
113
113
|
timestampCaughtUpToHeadOrEndblock: Js.null<Js.Date.t>,
|
|
114
114
|
@as("_is_hyper_sync") isHyperSync: bool,
|
|
@@ -122,6 +122,7 @@ module Chains = {
|
|
|
122
122
|
@as("max_reorg_depth") maxReorgDepth: int,
|
|
123
123
|
@as("progress_block") progressBlockNumber: int,
|
|
124
124
|
@as("events_processed") numEventsProcessed: int,
|
|
125
|
+
@as("source_block") blockHeight: int,
|
|
125
126
|
...metaFields,
|
|
126
127
|
}
|
|
127
128
|
|
|
@@ -212,7 +213,6 @@ VALUES ${valuesRows->Js.Array2.joinWith(",\n ")};`,
|
|
|
212
213
|
|
|
213
214
|
// Fields that can be updated outside of the batch transaction
|
|
214
215
|
let metaFields: array<field> = [
|
|
215
|
-
#source_block,
|
|
216
216
|
#buffer_block,
|
|
217
217
|
#first_event_block,
|
|
218
218
|
#ready_at,
|
|
@@ -279,7 +279,7 @@ FROM "${pgSchema}"."${table.tableName}" as chains;`
|
|
|
279
279
|
->(Utils.magic: promise<array<unknown>> => promise<array<rawInitialState>>)
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
let progressFields: array<progressFields> = [#progress_block, #events_processed]
|
|
282
|
+
let progressFields: array<progressFields> = [#progress_block, #events_processed, #source_block]
|
|
283
283
|
|
|
284
284
|
let makeProgressFieldsUpdateQuery = (~pgSchema) => {
|
|
285
285
|
let setClauses = Belt.Array.mapWithIndex(progressFields, (index, field) => {
|
|
@@ -320,6 +320,7 @@ WHERE "id" = $1;`
|
|
|
320
320
|
type progressedChain = {
|
|
321
321
|
chainId: int,
|
|
322
322
|
progressBlockNumber: int,
|
|
323
|
+
sourceBlockNumber: int,
|
|
323
324
|
totalEventsProcessed: int,
|
|
324
325
|
}
|
|
325
326
|
|
|
@@ -341,6 +342,7 @@ WHERE "id" = $1;`
|
|
|
341
342
|
switch field {
|
|
342
343
|
| #progress_block => data.progressBlockNumber->(Utils.magic: int => unknown)
|
|
343
344
|
| #events_processed => data.totalEventsProcessed->(Utils.magic: int => unknown)
|
|
345
|
+
| #source_block => data.sourceBlockNumber->(Utils.magic: int => unknown)
|
|
344
346
|
},
|
|
345
347
|
)
|
|
346
348
|
->ignore
|
|
@@ -101,9 +101,9 @@ function initialFromConfig(chainConfig) {
|
|
|
101
101
|
max_reorg_depth: chainConfig.maxReorgDepth,
|
|
102
102
|
progress_block: -1,
|
|
103
103
|
events_processed: 0,
|
|
104
|
+
source_block: 0,
|
|
104
105
|
first_event_block: null,
|
|
105
106
|
buffer_block: -1,
|
|
106
|
-
source_block: 0,
|
|
107
107
|
ready_at: null,
|
|
108
108
|
_is_hyper_sync: false,
|
|
109
109
|
_num_batches_fetched: 0
|
|
@@ -143,7 +143,6 @@ function makeInitialValuesQuery(pgSchema, chainConfigs) {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
var metaFields = [
|
|
146
|
-
"source_block",
|
|
147
146
|
"buffer_block",
|
|
148
147
|
"first_event_block",
|
|
149
148
|
"ready_at",
|
|
@@ -169,7 +168,8 @@ function getInitialState(sql, pgSchema) {
|
|
|
169
168
|
|
|
170
169
|
var progressFields = [
|
|
171
170
|
"progress_block",
|
|
172
|
-
"events_processed"
|
|
171
|
+
"events_processed",
|
|
172
|
+
"source_block"
|
|
173
173
|
];
|
|
174
174
|
|
|
175
175
|
function makeProgressFieldsUpdateQuery(pgSchema) {
|
|
@@ -202,7 +202,9 @@ function setProgressedChains(sql, pgSchema, progressedChains) {
|
|
|
202
202
|
var params = [];
|
|
203
203
|
params.push(data.chainId);
|
|
204
204
|
progressFields.forEach(function (field) {
|
|
205
|
-
params.push(field === "
|
|
205
|
+
params.push(field === "source_block" ? data.sourceBlockNumber : (
|
|
206
|
+
field === "progress_block" ? data.progressBlockNumber : data.totalEventsProcessed
|
|
207
|
+
));
|
|
206
208
|
});
|
|
207
209
|
promises.push(sql.unsafe(query, params, {prepare: true}));
|
|
208
210
|
});
|
package/src/sources/EvmChain.res
CHANGED
|
@@ -15,6 +15,7 @@ let getSyncConfig = (
|
|
|
15
15
|
?backoffMillis,
|
|
16
16
|
?queryTimeoutMillis,
|
|
17
17
|
?fallbackStallTimeout,
|
|
18
|
+
?pollingInterval,
|
|
18
19
|
}: Config.sourceSyncOptions,
|
|
19
20
|
): Config.sourceSync => {
|
|
20
21
|
let queryTimeoutMillis = queryTimeoutMillis->Option.getWithDefault(20_000)
|
|
@@ -39,6 +40,8 @@ let getSyncConfig = (
|
|
|
39
40
|
// How long to wait before cancelling an RPC request
|
|
40
41
|
queryTimeoutMillis,
|
|
41
42
|
fallbackStallTimeout: fallbackStallTimeout->Option.getWithDefault(queryTimeoutMillis / 2),
|
|
43
|
+
// How frequently to check for new blocks in realtime (default: 1000ms)
|
|
44
|
+
pollingInterval: pollingInterval->Option.getWithDefault(1000),
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -16,7 +16,8 @@ function getSyncConfig(param) {
|
|
|
16
16
|
intervalCeiling: Belt_Option.getWithDefault(Env.Configurable.SyncConfig.intervalCeiling, Belt_Option.getWithDefault(param.intervalCeiling, 10000)),
|
|
17
17
|
backoffMillis: Belt_Option.getWithDefault(param.backoffMillis, 5000),
|
|
18
18
|
queryTimeoutMillis: queryTimeoutMillis,
|
|
19
|
-
fallbackStallTimeout: Belt_Option.getWithDefault(param.fallbackStallTimeout, queryTimeoutMillis / 2 | 0)
|
|
19
|
+
fallbackStallTimeout: Belt_Option.getWithDefault(param.fallbackStallTimeout, queryTimeoutMillis / 2 | 0),
|
|
20
|
+
pollingInterval: Belt_Option.getWithDefault(param.pollingInterval, 1000)
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
|
package/src/sources/Rpc.res
CHANGED
|
@@ -183,30 +183,30 @@ module GetBlockHeight = {
|
|
|
183
183
|
module GetTransactionByHash = {
|
|
184
184
|
let transactionSchema = S.object((s): Internal.evmTransactionFields => {
|
|
185
185
|
// We already know the data so ignore the fields
|
|
186
|
-
// blockHash: ?s.field("blockHash", S.
|
|
187
|
-
// blockNumber: ?s.field("blockNumber", S.
|
|
188
|
-
// chainId: ?s.field("chainId", S.
|
|
189
|
-
from: ?s.field("from", S.
|
|
190
|
-
to: ?s.field("to", S.
|
|
191
|
-
gas: ?s.field("gas", S.
|
|
192
|
-
gasPrice: ?s.field("gasPrice", S.
|
|
193
|
-
hash: ?s.field("hash", S.
|
|
194
|
-
input: ?s.field("input", S.
|
|
195
|
-
nonce: ?s.field("nonce", S.
|
|
196
|
-
transactionIndex: ?s.field("transactionIndex", S.
|
|
197
|
-
value: ?s.field("value", S.
|
|
198
|
-
type_: ?s.field("type", S.
|
|
186
|
+
// blockHash: ?s.field("blockHash", S.nullable(S.string)),
|
|
187
|
+
// blockNumber: ?s.field("blockNumber", S.nullable(hexIntSchema)),
|
|
188
|
+
// chainId: ?s.field("chainId", S.nullable(hexIntSchema)),
|
|
189
|
+
from: ?s.field("from", S.nullable(S.string->(Utils.magic: S.t<string> => S.t<Address.t>))),
|
|
190
|
+
to: ?s.field("to", S.nullable(S.string->(Utils.magic: S.t<string> => S.t<Address.t>))),
|
|
191
|
+
gas: ?s.field("gas", S.nullable(hexBigintSchema)),
|
|
192
|
+
gasPrice: ?s.field("gasPrice", S.nullable(hexBigintSchema)),
|
|
193
|
+
hash: ?s.field("hash", S.nullable(S.string)),
|
|
194
|
+
input: ?s.field("input", S.nullable(S.string)),
|
|
195
|
+
nonce: ?s.field("nonce", S.nullable(hexBigintSchema)),
|
|
196
|
+
transactionIndex: ?s.field("transactionIndex", S.nullable(hexIntSchema)),
|
|
197
|
+
value: ?s.field("value", S.nullable(hexBigintSchema)),
|
|
198
|
+
type_: ?s.field("type", S.nullable(hexIntSchema)),
|
|
199
199
|
// Signature fields - optional for ZKSync EIP-712 compatibility
|
|
200
|
-
v: ?s.field("v", S.
|
|
201
|
-
r: ?s.field("r", S.
|
|
202
|
-
s: ?s.field("s", S.
|
|
203
|
-
yParity: ?s.field("yParity", S.
|
|
200
|
+
v: ?s.field("v", S.nullable(S.string)),
|
|
201
|
+
r: ?s.field("r", S.nullable(S.string)),
|
|
202
|
+
s: ?s.field("s", S.nullable(S.string)),
|
|
203
|
+
yParity: ?s.field("yParity", S.nullable(S.string)),
|
|
204
204
|
// EIP-1559 fields
|
|
205
|
-
maxPriorityFeePerGas: ?s.field("maxPriorityFeePerGas", S.
|
|
206
|
-
maxFeePerGas: ?s.field("maxFeePerGas", S.
|
|
205
|
+
maxPriorityFeePerGas: ?s.field("maxPriorityFeePerGas", S.nullable(hexBigintSchema)),
|
|
206
|
+
maxFeePerGas: ?s.field("maxFeePerGas", S.nullable(hexBigintSchema)),
|
|
207
207
|
// EIP-4844 blob fields
|
|
208
|
-
maxFeePerBlobGas: ?s.field("maxFeePerBlobGas", S.
|
|
209
|
-
blobVersionedHashes: ?s.field("blobVersionedHashes", S.
|
|
208
|
+
maxFeePerBlobGas: ?s.field("maxFeePerBlobGas", S.nullable(hexBigintSchema)),
|
|
209
|
+
blobVersionedHashes: ?s.field("blobVersionedHashes", S.nullable(S.array(S.string))),
|
|
210
210
|
// TODO: Fields to add:
|
|
211
211
|
// pub access_list: Option<Vec<AccessList>>,
|
|
212
212
|
// pub authorization_list: Option<Vec<Authorization>>,
|
package/src/sources/Rpc.res.mjs
CHANGED
|
@@ -189,24 +189,24 @@ var GetBlockHeight = {
|
|
|
189
189
|
|
|
190
190
|
var transactionSchema = S$RescriptSchema.object(function (s) {
|
|
191
191
|
return {
|
|
192
|
-
from: s.f("from", S$RescriptSchema.
|
|
193
|
-
to: s.f("to", S$RescriptSchema.
|
|
194
|
-
gas: s.f("gas", S$RescriptSchema.
|
|
195
|
-
gasPrice: s.f("gasPrice", S$RescriptSchema.
|
|
196
|
-
hash: s.f("hash", S$RescriptSchema.
|
|
197
|
-
input: s.f("input", S$RescriptSchema.
|
|
198
|
-
nonce: s.f("nonce", S$RescriptSchema.
|
|
199
|
-
transactionIndex: s.f("transactionIndex", S$RescriptSchema.
|
|
200
|
-
value: s.f("value", S$RescriptSchema.
|
|
201
|
-
v: s.f("v", S$RescriptSchema.
|
|
202
|
-
r: s.f("r", S$RescriptSchema.
|
|
203
|
-
s: s.f("s", S$RescriptSchema.
|
|
204
|
-
yParity: s.f("yParity", S$RescriptSchema.
|
|
205
|
-
maxPriorityFeePerGas: s.f("maxPriorityFeePerGas", S$RescriptSchema.
|
|
206
|
-
maxFeePerGas: s.f("maxFeePerGas", S$RescriptSchema.
|
|
207
|
-
maxFeePerBlobGas: s.f("maxFeePerBlobGas", S$RescriptSchema.
|
|
208
|
-
blobVersionedHashes: s.f("blobVersionedHashes", S$RescriptSchema.
|
|
209
|
-
type: s.f("type", S$RescriptSchema.
|
|
192
|
+
from: s.f("from", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
193
|
+
to: s.f("to", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
194
|
+
gas: s.f("gas", S$RescriptSchema.nullable(hexBigintSchema)),
|
|
195
|
+
gasPrice: s.f("gasPrice", S$RescriptSchema.nullable(hexBigintSchema)),
|
|
196
|
+
hash: s.f("hash", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
197
|
+
input: s.f("input", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
198
|
+
nonce: s.f("nonce", S$RescriptSchema.nullable(hexBigintSchema)),
|
|
199
|
+
transactionIndex: s.f("transactionIndex", S$RescriptSchema.nullable(hexIntSchema)),
|
|
200
|
+
value: s.f("value", S$RescriptSchema.nullable(hexBigintSchema)),
|
|
201
|
+
v: s.f("v", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
202
|
+
r: s.f("r", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
203
|
+
s: s.f("s", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
204
|
+
yParity: s.f("yParity", S$RescriptSchema.nullable(S$RescriptSchema.string)),
|
|
205
|
+
maxPriorityFeePerGas: s.f("maxPriorityFeePerGas", S$RescriptSchema.nullable(hexBigintSchema)),
|
|
206
|
+
maxFeePerGas: s.f("maxFeePerGas", S$RescriptSchema.nullable(hexBigintSchema)),
|
|
207
|
+
maxFeePerBlobGas: s.f("maxFeePerBlobGas", S$RescriptSchema.nullable(hexBigintSchema)),
|
|
208
|
+
blobVersionedHashes: s.f("blobVersionedHashes", S$RescriptSchema.nullable(S$RescriptSchema.array(S$RescriptSchema.string))),
|
|
209
|
+
type: s.f("type", S$RescriptSchema.nullable(hexIntSchema))
|
|
210
210
|
};
|
|
211
211
|
});
|
|
212
212
|
|
|
@@ -16,49 +16,50 @@ let getKnownBlock = (provider, blockNumber) =>
|
|
|
16
16
|
}
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
-
let
|
|
19
|
+
let getKnownBlockWithBackoff = async (
|
|
20
20
|
~provider,
|
|
21
21
|
~sourceName,
|
|
22
22
|
~chain,
|
|
23
23
|
~blockNumber,
|
|
24
24
|
~backoffMsOnFailure,
|
|
25
25
|
~lowercaseAddresses: bool,
|
|
26
|
-
) =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
~
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
| result =>
|
|
46
|
-
if lowercaseAddresses {
|
|
26
|
+
) => {
|
|
27
|
+
let currentBackoff = ref(backoffMsOnFailure)
|
|
28
|
+
let result = ref(None)
|
|
29
|
+
|
|
30
|
+
while result.contents->Option.isNone {
|
|
31
|
+
Prometheus.SourceRequestCount.increment(~sourceName, ~chainId=chain->ChainMap.Chain.toChainId)
|
|
32
|
+
switch await getKnownBlock(provider, blockNumber) {
|
|
33
|
+
| exception err =>
|
|
34
|
+
Logging.warn({
|
|
35
|
+
"err": err->Utils.prettifyExn,
|
|
36
|
+
"msg": `Issue while running fetching batch of events from the RPC. Will wait ${currentBackoff.contents->Belt.Int.toString}ms and try again.`,
|
|
37
|
+
"source": sourceName,
|
|
38
|
+
"chainId": chain->ChainMap.Chain.toChainId,
|
|
39
|
+
"type": "EXPONENTIAL_BACKOFF",
|
|
40
|
+
})
|
|
41
|
+
await Time.resolvePromiseAfterDelay(~delayMilliseconds=currentBackoff.contents)
|
|
42
|
+
currentBackoff := currentBackoff.contents * 2
|
|
43
|
+
| block =>
|
|
47
44
|
// NOTE: this is wasteful if these fields are not selected in the users config.
|
|
48
45
|
// There might be a better way to do this based on the block schema.
|
|
49
46
|
// However this is not extremely expensive and good enough for now (only on rpc sync also).
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
// Mutation would be cheaper,
|
|
48
|
+
// BUT "block" is an Ethers.js Block object,
|
|
49
|
+
// which has the fields as readonly.
|
|
50
|
+
result :=
|
|
51
|
+
Some({
|
|
52
|
+
...block,
|
|
53
|
+
miner: if lowercaseAddresses {
|
|
54
|
+
block.miner->Address.Evm.fromAddressLowercaseOrThrow
|
|
55
|
+
} else {
|
|
56
|
+
block.miner->Address.Evm.fromAddressOrThrow
|
|
57
|
+
},
|
|
58
|
+
})
|
|
60
59
|
}
|
|
61
60
|
}
|
|
61
|
+
result.contents->Option.getExn
|
|
62
|
+
}
|
|
62
63
|
let getSuggestedBlockIntervalFromExn = {
|
|
63
64
|
// Unknown provider: "retry with the range 123-456"
|
|
64
65
|
let suggestedRangeRegExp = %re(`/retry with the range (\d+)-(\d+)/`)
|
|
@@ -505,8 +506,7 @@ let make = (
|
|
|
505
506
|
|
|
506
507
|
let makeBlockLoader = () =>
|
|
507
508
|
LazyLoader.make(
|
|
508
|
-
~loaderFn=blockNumber =>
|
|
509
|
-
Prometheus.SourceRequestCount.increment(~sourceName=name, ~chainId=chain->ChainMap.Chain.toChainId)
|
|
509
|
+
~loaderFn=blockNumber =>
|
|
510
510
|
getKnownBlockWithBackoff(
|
|
511
511
|
~provider,
|
|
512
512
|
~sourceName=name,
|
|
@@ -514,8 +514,7 @@ let make = (
|
|
|
514
514
|
~backoffMsOnFailure=1000,
|
|
515
515
|
~blockNumber,
|
|
516
516
|
~lowercaseAddresses,
|
|
517
|
-
)
|
|
518
|
-
},
|
|
517
|
+
),
|
|
519
518
|
~onError=(am, ~exn) => {
|
|
520
519
|
Logging.error({
|
|
521
520
|
"err": exn->Utils.prettifyExn,
|
|
@@ -682,7 +681,7 @@ let make = (
|
|
|
682
681
|
let routedAddress = if lowercaseAddresses {
|
|
683
682
|
log.address->Address.Evm.fromAddressLowercaseOrThrow
|
|
684
683
|
} else {
|
|
685
|
-
log.address
|
|
684
|
+
log.address->Address.Evm.fromAddressOrThrow
|
|
686
685
|
}
|
|
687
686
|
|
|
688
687
|
switch eventRouter->EventRouter.get(
|
|
@@ -804,7 +803,7 @@ let make = (
|
|
|
804
803
|
sourceFor,
|
|
805
804
|
chain,
|
|
806
805
|
poweredByHyperSync: false,
|
|
807
|
-
pollingInterval:
|
|
806
|
+
pollingInterval: syncConfig.pollingInterval,
|
|
808
807
|
getBlockHashes,
|
|
809
808
|
getHeightOrThrow: () => {
|
|
810
809
|
Prometheus.SourceRequestCount.increment(~sourceName=name, ~chainId=chain->ChainMap.Chain.toChainId)
|
|
@@ -40,40 +40,47 @@ function getKnownBlock(provider, blockNumber) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
async function getKnownBlockWithBackoff(provider, sourceName, chain, blockNumber, backoffMsOnFailure, lowercaseAddresses) {
|
|
43
|
+
var currentBackoff = backoffMsOnFailure;
|
|
43
44
|
var result;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
45
|
+
while(Belt_Option.isNone(result)) {
|
|
46
|
+
Prometheus.SourceRequestCount.increment(sourceName, chain);
|
|
47
|
+
var exit = 0;
|
|
48
|
+
var block;
|
|
49
|
+
try {
|
|
50
|
+
block = await getKnownBlock(provider, blockNumber);
|
|
51
|
+
exit = 1;
|
|
52
|
+
}
|
|
53
|
+
catch (raw_err){
|
|
54
|
+
var err = Caml_js_exceptions.internalToOCamlException(raw_err);
|
|
55
|
+
Logging.warn({
|
|
56
|
+
err: Utils.prettifyExn(err),
|
|
57
|
+
msg: "Issue while running fetching batch of events from the RPC. Will wait " + String(currentBackoff) + "ms and try again.",
|
|
58
|
+
source: sourceName,
|
|
59
|
+
chainId: chain,
|
|
60
|
+
type: "EXPONENTIAL_BACKOFF"
|
|
61
|
+
});
|
|
62
|
+
await Time.resolvePromiseAfterDelay(currentBackoff);
|
|
63
|
+
currentBackoff = (currentBackoff << 1);
|
|
64
|
+
}
|
|
65
|
+
if (exit === 1) {
|
|
66
|
+
result = {
|
|
67
|
+
_difficulty: block._difficulty,
|
|
68
|
+
difficulty: block.difficulty,
|
|
69
|
+
extraData: block.extraData,
|
|
70
|
+
gasLimit: block.gasLimit,
|
|
71
|
+
gasUsed: block.gasUsed,
|
|
72
|
+
hash: block.hash,
|
|
73
|
+
miner: lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(block.miner) : Address.Evm.fromAddressOrThrow(block.miner),
|
|
74
|
+
nonce: block.nonce,
|
|
75
|
+
number: block.number,
|
|
76
|
+
parentHash: block.parentHash,
|
|
77
|
+
timestamp: block.timestamp,
|
|
78
|
+
transactions: block.transactions
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
};
|
|
83
|
+
return Belt_Option.getExn(result);
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
var suggestedRangeRegExp = /retry with the range (\d+)-(\d+)/;
|
|
@@ -525,7 +532,6 @@ function make(param) {
|
|
|
525
532
|
};
|
|
526
533
|
var makeBlockLoader = function () {
|
|
527
534
|
return LazyLoader.make((function (blockNumber) {
|
|
528
|
-
Prometheus.SourceRequestCount.increment(name, chain);
|
|
529
535
|
return getKnownBlockWithBackoff(provider, name, chain, blockNumber, 1000, lowercaseAddresses);
|
|
530
536
|
}), (function (am, exn) {
|
|
531
537
|
Logging.error({
|
|
@@ -640,7 +646,7 @@ function make(param) {
|
|
|
640
646
|
var maybeDecodedEvent = param[1];
|
|
641
647
|
var log = param[0];
|
|
642
648
|
var topic0 = Belt_Option.getWithDefault(Belt_Array.get(log.topics, 0), "0x0");
|
|
643
|
-
var routedAddress = lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(log.address) : log.address;
|
|
649
|
+
var routedAddress = lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(log.address) : Address.Evm.fromAddressOrThrow(log.address);
|
|
644
650
|
var eventConfig = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), routedAddress, log.blockNumber, indexingContracts);
|
|
645
651
|
if (eventConfig !== undefined && !(maybeDecodedEvent === null || maybeDecodedEvent === undefined)) {
|
|
646
652
|
return Caml_option.some((async function () {
|
|
@@ -742,7 +748,7 @@ function make(param) {
|
|
|
742
748
|
sourceFor: param.sourceFor,
|
|
743
749
|
chain: chain,
|
|
744
750
|
poweredByHyperSync: false,
|
|
745
|
-
pollingInterval:
|
|
751
|
+
pollingInterval: syncConfig.pollingInterval,
|
|
746
752
|
getBlockHashes: getBlockHashes,
|
|
747
753
|
getHeightOrThrow: (function () {
|
|
748
754
|
Prometheus.SourceRequestCount.increment(name, chain);
|