envio 3.15.0 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -34
- package/evm.schema.json +11 -2
- package/fuel.schema.json +10 -1
- package/index.d.ts +6 -0
- package/licenses/README.md +1 -1
- package/package.json +8 -8
- package/src/Batch.res.mjs +5 -5
- package/src/BatchProcessing.res +1 -0
- package/src/BatchProcessing.res.mjs +1 -0
- package/src/ChainState.res +48 -7
- package/src/ChainState.res.mjs +27 -11
- package/src/Clock.res +57 -0
- package/src/Clock.res.mjs +72 -0
- package/src/Config.res +10 -3
- package/src/Config.res.mjs +4 -2
- package/src/Core.res +4 -40
- package/src/EffectState.res +10 -2
- package/src/EffectState.res.mjs +8 -4
- package/src/EffectState.resi +3 -1
- package/src/EntityId.res +2 -7
- package/src/EntityId.res.mjs +1 -8
- package/src/EntityTables.res +4 -1
- package/src/EntityTables.res.mjs +1 -1
- package/src/FetchState.res +157 -69
- package/src/FetchState.res.mjs +144 -49
- package/src/FinalizeBackfill.res +2 -4
- package/src/FinalizeBackfill.res.mjs +3 -4
- package/src/InMemoryTable.res +17 -16
- package/src/InMemoryTable.res.mjs +14 -15
- package/src/IndexerState.res +28 -4
- package/src/IndexerState.res.mjs +19 -6
- package/src/IndexerState.resi +4 -0
- package/src/Internal.res +0 -49
- package/src/Internal.res.mjs +1 -80
- package/src/LoadLayer.res +14 -8
- package/src/LoadLayer.res.mjs +8 -6
- package/src/Main.res.mjs +1 -1
- package/src/Persistence.res +3 -23
- package/src/Persistence.res.mjs +3 -3
- package/src/Rollback.res +0 -1
- package/src/Rollback.res.mjs +1 -1
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +1 -1
- package/src/StagedRows.res +106 -0
- package/src/StagedRows.res.mjs +102 -0
- package/src/Staging.res +32 -14
- package/src/Staging.res.mjs +17 -20
- package/src/Storage.res +277 -948
- package/src/Storage.res.mjs +215 -707
- package/src/Supervisor.res +75 -56
- package/src/Supervisor.res.mjs +55 -26
- package/src/TestIndexer.res +22 -27
- package/src/TestIndexer.res.mjs +20 -17
- package/src/Throttler.res +15 -8
- package/src/Throttler.res.mjs +9 -6
- package/src/Throttler.resi +1 -1
- package/src/Utils.res +0 -6
- package/src/Utils.res.mjs +0 -5
- package/src/Writing.res +0 -1
- package/src/Writing.res.mjs +1 -1
- package/src/bindings/ClickHouse.res +0 -322
- package/src/bindings/ClickHouse.res.mjs +0 -338
- package/src/bindings/StorageClient.res +107 -174
- package/src/bindings/StorageClient.res.mjs +19 -8
- package/src/bindings/Vitest.res +0 -26
- package/src/bindings/Vitest.res.mjs +0 -3
- package/src/db/Table.res +24 -150
- package/src/db/Table.res.mjs +38 -272
- package/src/sources/ChainSources.res +2 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +3 -0
- package/src/sources/EvmChain.res.mjs +4 -2
- package/src/sources/EvmHyperSyncSource.res +2 -2
- package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
- package/src/sources/EvmRpcClient.res +13 -3
- package/src/sources/EvmRpcClient.res.mjs +4 -3
- package/src/sources/EvmRpcWs.res +4 -3
- package/src/sources/EvmRpcWs.res.mjs +2 -2
- package/src/sources/HeightFeed.res +31 -10
- package/src/sources/HeightFeed.res.mjs +10 -6
- package/src/sources/HeightStream.res +32 -17
- package/src/sources/HeightStream.res.mjs +10 -10
- package/src/sources/HyperSyncSSE.res +4 -6
- package/src/sources/HyperSyncSSE.res.mjs +2 -2
- package/src/sources/RpcSource.res +10 -1
- package/src/sources/RpcSource.res.mjs +4 -3
- package/src/sources/Source.res +3 -0
- package/src/sources/SourceManager.res +84 -77
- package/src/sources/SourceManager.res.mjs +17 -20
- package/src/sources/SourceManager.resi +3 -4
- package/src/sources/StartBlockResolver.res +1 -0
- package/src/sources/StartBlockResolver.res.mjs +3 -2
- package/src/sources/SvmHyperSyncSource.res +2 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/svm.schema.json +11 -2
- package/src/PgWriting.res +0 -36
- package/src/PgWriting.res.mjs +0 -34
- package/src/db/IndexDefinition.res +0 -47
- package/src/db/IndexDefinition.res.mjs +0 -67
|
@@ -8,6 +8,7 @@ type cfg = {
|
|
|
8
8
|
intervalCeiling: int,
|
|
9
9
|
backoffMillis: int,
|
|
10
10
|
queryTimeoutMillis: int,
|
|
11
|
+
maxAddressesPerRequest: int,
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
type nextPageParams = {
|
|
@@ -18,10 +19,12 @@ type nextPageParams = {
|
|
|
18
19
|
onBlockRegistrationIndexes: array<int>,
|
|
19
20
|
clientFilteredContracts: option<array<string>>,
|
|
20
21
|
retry: int,
|
|
21
|
-
// Blocks at or above this one can still be reorged, so
|
|
22
|
-
//
|
|
23
|
-
// handler block in range. None when the range is
|
|
22
|
+
// Blocks at or above this one can still be reorged, so each of them in the
|
|
23
|
+
// page has its header read and its logs checked against it, even a
|
|
24
|
+
// blocks-only page with no handler block in range. None when the range is
|
|
25
|
+
// final.
|
|
24
26
|
reorgableFrom?: int,
|
|
27
|
+
knownHeight: int,
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
// Rust reports what to do about a page it could not read rather than throwing
|
|
@@ -77,6 +80,8 @@ external classNew: (
|
|
|
77
80
|
array<BlockItem.registrationInput>,
|
|
78
81
|
~checksumAddresses: bool,
|
|
79
82
|
~addressStore: AddressStore.t,
|
|
83
|
+
Logger.native,
|
|
84
|
+
array<string>,
|
|
80
85
|
) => t = "new"
|
|
81
86
|
|
|
82
87
|
let make = (
|
|
@@ -88,6 +93,8 @@ let make = (
|
|
|
88
93
|
~eventRegistrations=[],
|
|
89
94
|
~onBlockRegistrations=[],
|
|
90
95
|
~addressStore,
|
|
96
|
+
~maxAddressesPerRequest,
|
|
97
|
+
~logger: Logger.t,
|
|
91
98
|
) =>
|
|
92
99
|
Core.getAddon().evmRpcClient->classNew(
|
|
93
100
|
{
|
|
@@ -100,9 +107,12 @@ let make = (
|
|
|
100
107
|
intervalCeiling: syncConfig.intervalCeiling,
|
|
101
108
|
backoffMillis: syncConfig.backoffMillis,
|
|
102
109
|
queryTimeoutMillis: syncConfig.queryTimeoutMillis,
|
|
110
|
+
maxAddressesPerRequest,
|
|
103
111
|
},
|
|
104
112
|
eventRegistrations,
|
|
105
113
|
onBlockRegistrations->BlockItem.toRegistrationInputs,
|
|
106
114
|
~checksumAddresses,
|
|
107
115
|
~addressStore,
|
|
116
|
+
logger.output.native,
|
|
117
|
+
logger.boundFieldsJson,
|
|
108
118
|
)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import * as Core from "../Core.res.mjs";
|
|
4
4
|
import * as BlockItem from "./BlockItem.res.mjs";
|
|
5
5
|
|
|
6
|
-
function make(url, checksumAddresses, syncConfig, maxConcurrentRequests, headers, eventRegistrationsOpt, onBlockRegistrationsOpt, addressStore) {
|
|
6
|
+
function make(url, checksumAddresses, syncConfig, maxConcurrentRequests, headers, eventRegistrationsOpt, onBlockRegistrationsOpt, addressStore, maxAddressesPerRequest, logger) {
|
|
7
7
|
let eventRegistrations = eventRegistrationsOpt !== undefined ? eventRegistrationsOpt : [];
|
|
8
8
|
let onBlockRegistrations = onBlockRegistrationsOpt !== undefined ? onBlockRegistrationsOpt : [];
|
|
9
9
|
return Core.getAddon().EvmRpcClient.new({
|
|
@@ -15,8 +15,9 @@ function make(url, checksumAddresses, syncConfig, maxConcurrentRequests, headers
|
|
|
15
15
|
accelerationAdditive: syncConfig.accelerationAdditive,
|
|
16
16
|
intervalCeiling: syncConfig.intervalCeiling,
|
|
17
17
|
backoffMillis: syncConfig.backoffMillis,
|
|
18
|
-
queryTimeoutMillis: syncConfig.queryTimeoutMillis
|
|
19
|
-
|
|
18
|
+
queryTimeoutMillis: syncConfig.queryTimeoutMillis,
|
|
19
|
+
maxAddressesPerRequest: maxAddressesPerRequest
|
|
20
|
+
}, eventRegistrations, BlockItem.toRegistrationInputs(onBlockRegistrations), checksumAddresses, addressStore, logger.output.native, logger.boundFieldsJson);
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export {
|
package/src/sources/EvmRpcWs.res
CHANGED
|
@@ -81,8 +81,8 @@ let wsMessageSchema = S.union([
|
|
|
81
81
|
}),
|
|
82
82
|
])
|
|
83
83
|
|
|
84
|
-
let subscribe = (~wsUrl, ~onHeight, ~onStatus) =>
|
|
85
|
-
HeightStream.subscribe(~staleTimeout, ~onHeight, ~onStatus, ~connect=driver => {
|
|
84
|
+
let subscribe = (~clock, ~wsUrl, ~onHeight, ~onStatus) =>
|
|
85
|
+
HeightStream.subscribe(~clock, ~staleTimeout, ~onHeight, ~onStatus, ~connect=driver => {
|
|
86
86
|
let ws = WebSocket.create(wsUrl)
|
|
87
87
|
let subscribed = ref(false)
|
|
88
88
|
|
|
@@ -103,7 +103,8 @@ let subscribe = (~wsUrl, ~onHeight, ~onStatus) =>
|
|
|
103
103
|
| Some(Response({id: Some(id), isError: false})) if id === subscribeRequestIdText =>
|
|
104
104
|
subscribed := true
|
|
105
105
|
driver.onConnected()
|
|
106
|
-
| Some(Response({id, isError: true}))
|
|
106
|
+
| Some(Response({id, isError: true}))
|
|
107
|
+
if id->refusesSubscribe(~subscribed=subscribed.contents) =>
|
|
107
108
|
driver.onFailure(~reason=SubscribeRejected, ~detail=text)
|
|
108
109
|
// A provider talking about something other than the subscription this
|
|
109
110
|
// socket asked for — a rate limit, a request nobody here made. Read
|
|
@@ -61,8 +61,8 @@ let wsMessageSchema = S$RescriptSchema.union([
|
|
|
61
61
|
})
|
|
62
62
|
]);
|
|
63
63
|
|
|
64
|
-
function subscribe(wsUrl, onHeight, onStatus) {
|
|
65
|
-
return HeightStream.subscribe(60000, onHeight, onStatus, driver => {
|
|
64
|
+
function subscribe(clock, wsUrl, onHeight, onStatus) {
|
|
65
|
+
return HeightStream.subscribe(clock, 60000, onHeight, onStatus, driver => {
|
|
66
66
|
let ws = new WebSocket(wsUrl);
|
|
67
67
|
let subscribed = {
|
|
68
68
|
contents: false
|
|
@@ -79,6 +79,7 @@ type t = {
|
|
|
79
79
|
// than any healthy getHeight, so a merely slow endpoint answers first and
|
|
80
80
|
// nothing here fires in normal running.
|
|
81
81
|
pollTimeoutMillis: int,
|
|
82
|
+
clock: Clock.t,
|
|
82
83
|
mutable knownHeight: int,
|
|
83
84
|
mutable waiters: array<waiter>,
|
|
84
85
|
mutable stream: streamState,
|
|
@@ -110,12 +111,14 @@ let make = (
|
|
|
110
111
|
~recordRequestStats,
|
|
111
112
|
~getHeightRetryInterval,
|
|
112
113
|
~pollTimeoutMillis,
|
|
114
|
+
~clock,
|
|
113
115
|
): t => {
|
|
114
116
|
source,
|
|
115
117
|
logger: logger->Logger.withFields({"source": source.name}),
|
|
116
118
|
recordRequestStats,
|
|
117
119
|
getHeightRetryInterval,
|
|
118
120
|
pollTimeoutMillis,
|
|
121
|
+
clock,
|
|
119
122
|
knownHeight: 0,
|
|
120
123
|
waiters: [],
|
|
121
124
|
stream: NeverEnabled,
|
|
@@ -275,26 +278,43 @@ let heightWithin = (feed: t): promise<pollOutcome> => {
|
|
|
275
278
|
request
|
|
276
279
|
->Promise.thenResolve(res => Answered(res))
|
|
277
280
|
->Promise.catch(exn => Promise.resolve(Failed(exn))),
|
|
278
|
-
Promise.make((resolve, _reject) =>
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
281
|
+
Promise.make((resolve, _reject) =>
|
|
282
|
+
timeoutId :=
|
|
283
|
+
Some(
|
|
284
|
+
feed.clock.setTimeout(
|
|
285
|
+
~label="height poll timeout",
|
|
286
|
+
() => {
|
|
287
|
+
timedOut := true
|
|
288
|
+
resolve(TimedOut)
|
|
289
|
+
},
|
|
290
|
+
feed.pollTimeoutMillis,
|
|
291
|
+
),
|
|
292
|
+
)
|
|
293
|
+
),
|
|
282
294
|
])->Promise.thenResolve(outcome => {
|
|
283
|
-
|
|
295
|
+
feed.clock->Clock.clearRef(timeoutId)
|
|
284
296
|
outcome
|
|
285
297
|
})
|
|
286
298
|
}
|
|
287
299
|
|
|
288
300
|
let sleep = (feed: t, ~kind, millis) =>
|
|
289
301
|
Promise.make((resolve, _reject) => {
|
|
290
|
-
let
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
302
|
+
let label = switch kind {
|
|
303
|
+
| Cadence => "height poll cadence"
|
|
304
|
+
| Backoff => "height poll backoff"
|
|
305
|
+
}
|
|
306
|
+
let timer = feed.clock.setTimeout(
|
|
307
|
+
~label,
|
|
308
|
+
() => {
|
|
309
|
+
feed.sleeping = None
|
|
310
|
+
resolve()
|
|
311
|
+
},
|
|
312
|
+
millis,
|
|
313
|
+
)
|
|
294
314
|
feed.sleeping = Some({
|
|
295
315
|
kind,
|
|
296
316
|
wake: () => {
|
|
297
|
-
clearTimeout(
|
|
317
|
+
feed.clock.clearTimeout(timer)
|
|
298
318
|
feed.sleeping = None
|
|
299
319
|
resolve()
|
|
300
320
|
},
|
|
@@ -521,6 +541,7 @@ let enableStream = (feed: t) =>
|
|
|
521
541
|
}
|
|
522
542
|
feed.closeStream = Some(
|
|
523
543
|
createSubscription(
|
|
544
|
+
~clock=feed.clock,
|
|
524
545
|
~onHeight=height => feed->handlePushedHeight(height),
|
|
525
546
|
~onStatus=status => feed->handleStatus(status),
|
|
526
547
|
),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Clock from "../Clock.res.mjs";
|
|
3
4
|
import * as Utils from "../Utils.res.mjs";
|
|
4
5
|
import * as Logger from "../Logger.res.mjs";
|
|
5
6
|
import * as Source from "./Source.res.mjs";
|
|
@@ -10,7 +11,7 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
|
|
|
10
11
|
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
11
12
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
12
13
|
|
|
13
|
-
function make(source, logger, recordRequestStats, getHeightRetryInterval, pollTimeoutMillis) {
|
|
14
|
+
function make(source, logger, recordRequestStats, getHeightRetryInterval, pollTimeoutMillis, clock) {
|
|
14
15
|
return {
|
|
15
16
|
source: source,
|
|
16
17
|
logger: Logger.withFields(logger, {
|
|
@@ -19,6 +20,7 @@ function make(source, logger, recordRequestStats, getHeightRetryInterval, pollTi
|
|
|
19
20
|
recordRequestStats: recordRequestStats,
|
|
20
21
|
getHeightRetryInterval: getHeightRetryInterval,
|
|
21
22
|
pollTimeoutMillis: pollTimeoutMillis,
|
|
23
|
+
clock: clock,
|
|
22
24
|
knownHeight: 0,
|
|
23
25
|
waiters: [],
|
|
24
26
|
stream: "NeverEnabled",
|
|
@@ -157,27 +159,29 @@ function heightWithin(feed) {
|
|
|
157
159
|
_0: exn
|
|
158
160
|
})),
|
|
159
161
|
new Promise((resolve, _reject) => {
|
|
160
|
-
timeoutId.contents = Primitive_option.some(setTimeout(() => {
|
|
162
|
+
timeoutId.contents = Primitive_option.some(feed.clock.setTimeout("height poll timeout", () => {
|
|
161
163
|
timedOut.contents = true;
|
|
162
164
|
resolve("TimedOut");
|
|
163
165
|
}, feed.pollTimeoutMillis));
|
|
164
166
|
})
|
|
165
167
|
]).then(outcome => {
|
|
166
|
-
|
|
168
|
+
Clock.clearRef(feed.clock, timeoutId);
|
|
167
169
|
return outcome;
|
|
168
170
|
});
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
function sleep(feed, kind, millis) {
|
|
172
174
|
return new Promise((resolve, _reject) => {
|
|
173
|
-
let
|
|
175
|
+
let label;
|
|
176
|
+
label = kind === "Cadence" ? "height poll cadence" : "height poll backoff";
|
|
177
|
+
let timer = feed.clock.setTimeout(label, () => {
|
|
174
178
|
feed.sleeping = undefined;
|
|
175
179
|
resolve();
|
|
176
180
|
}, millis);
|
|
177
181
|
feed.sleeping = {
|
|
178
182
|
kind: kind,
|
|
179
183
|
wake: () => {
|
|
180
|
-
clearTimeout(
|
|
184
|
+
feed.clock.clearTimeout(timer);
|
|
181
185
|
feed.sleeping = undefined;
|
|
182
186
|
resolve();
|
|
183
187
|
}
|
|
@@ -370,7 +374,7 @@ function enableStream(feed) {
|
|
|
370
374
|
if (typeof match$2 !== "object" && match$2 === "NeverEnabled") {
|
|
371
375
|
feed.stream = "Disconnected";
|
|
372
376
|
}
|
|
373
|
-
feed.closeStream = match(height => handlePushedHeight(feed, height), status => handleStatus(feed, status));
|
|
377
|
+
feed.closeStream = match(feed.clock, height => handlePushedHeight(feed, height), status => handleStatus(feed, status));
|
|
374
378
|
}
|
|
375
379
|
|
|
376
380
|
function stop(feed) {
|
|
@@ -58,6 +58,7 @@ let truncateDetail = detail =>
|
|
|
58
58
|
: detail
|
|
59
59
|
|
|
60
60
|
let subscribe = (
|
|
61
|
+
~clock: Clock.t,
|
|
61
62
|
~staleTimeout: int,
|
|
62
63
|
~onHeight: int => unit,
|
|
63
64
|
~onStatus: Source.heightSubscriptionStatus => unit,
|
|
@@ -85,7 +86,7 @@ let subscribe = (
|
|
|
85
86
|
let liveAt = ref(None)
|
|
86
87
|
let minProvenMillis = staleTimeout / provenStaleFraction
|
|
87
88
|
|
|
88
|
-
let clearPendingTimeout = () =>
|
|
89
|
+
let clearPendingTimeout = () => clock->Clock.clearRef(timeoutId)
|
|
89
90
|
|
|
90
91
|
// A transport that throws while closing must not be able to stop the retry
|
|
91
92
|
// that follows, nor escape a timer callback and take the process down. Every
|
|
@@ -106,15 +107,22 @@ let subscribe = (
|
|
|
106
107
|
|
|
107
108
|
let rec armStaleTimeout = () => {
|
|
108
109
|
clearPendingTimeout()
|
|
109
|
-
timeoutId :=
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
110
|
+
timeoutId :=
|
|
111
|
+
Some(
|
|
112
|
+
clock.setTimeout(
|
|
113
|
+
~label="height stream stale",
|
|
114
|
+
() => {
|
|
115
|
+
timeoutId := None
|
|
116
|
+
// Distinguishes a provider whose message shape we don't understand
|
|
117
|
+
// from a chain that simply has nothing to report.
|
|
118
|
+
switch unreadableDetail.contents {
|
|
119
|
+
| Some(detail) => fail(~reason=Source.Unreadable, ~detail)
|
|
120
|
+
| None => fail(~reason=Source.Stale)
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
staleTimeout,
|
|
124
|
+
),
|
|
125
|
+
)
|
|
118
126
|
}
|
|
119
127
|
and fail = (~reason: Source.heightSubscriptionDownReason, ~detail=?) => {
|
|
120
128
|
generation := generation.contents + 1
|
|
@@ -128,7 +136,7 @@ let subscribe = (
|
|
|
128
136
|
// bar rises with the backoff, so an endpoint that always dies at the same
|
|
129
137
|
// age keeps escalating rather than settling into a loop at a fixed delay.
|
|
130
138
|
let servedMillis = switch liveAt.contents {
|
|
131
|
-
| Some(since) => (
|
|
139
|
+
| Some(since) => (clock.now() -. since)->Float.toInt
|
|
132
140
|
| None => 0
|
|
133
141
|
}
|
|
134
142
|
// Against the schedule, not against the jittered wait actually served. The
|
|
@@ -143,7 +151,7 @@ let subscribe = (
|
|
|
143
151
|
failureCount.contents + 1
|
|
144
152
|
}
|
|
145
153
|
|
|
146
|
-
let retryMillis = retryDelayFor(failureCount.contents)
|
|
154
|
+
let retryMillis = clock->Clock.jitter(retryDelayFor(failureCount.contents))
|
|
147
155
|
|
|
148
156
|
// A clean end to a connection that had proven itself is a rotation: routine,
|
|
149
157
|
// and worth telling apart from the same clean end arriving early, which is a
|
|
@@ -157,10 +165,17 @@ let subscribe = (
|
|
|
157
165
|
|
|
158
166
|
// Scheduled before reporting, so a consumer that throws can't be what makes
|
|
159
167
|
// the stream give up.
|
|
160
|
-
timeoutId :=
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
timeoutId :=
|
|
169
|
+
Some(
|
|
170
|
+
clock.setTimeout(
|
|
171
|
+
~label="height stream retry",
|
|
172
|
+
() => {
|
|
173
|
+
timeoutId := None
|
|
174
|
+
start()
|
|
175
|
+
},
|
|
176
|
+
retryMillis,
|
|
177
|
+
),
|
|
178
|
+
)
|
|
164
179
|
|
|
165
180
|
onStatus(Down({reason, detail: ?(detail->Option.map(truncateDetail))}))
|
|
166
181
|
}
|
|
@@ -183,7 +198,7 @@ let subscribe = (
|
|
|
183
198
|
let goLive = () => {
|
|
184
199
|
armStaleTimeout()
|
|
185
200
|
if liveAt.contents->Option.isNone {
|
|
186
|
-
liveAt := Some(
|
|
201
|
+
liveAt := Some(clock.now())
|
|
187
202
|
onStatus(Live)
|
|
188
203
|
}
|
|
189
204
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Clock from "../Clock.res.mjs";
|
|
3
4
|
import * as Utils from "../Utils.res.mjs";
|
|
4
|
-
import * as Performance from "../bindings/Performance.res.mjs";
|
|
5
5
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
6
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
7
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
@@ -23,7 +23,7 @@ function truncateDetail(detail) {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function subscribe(staleTimeout, onHeight, onStatus, connect) {
|
|
26
|
+
function subscribe(clock, staleTimeout, onHeight, onStatus, connect) {
|
|
27
27
|
let closeConnectionRef = {
|
|
28
28
|
contents: undefined
|
|
29
29
|
};
|
|
@@ -58,8 +58,8 @@ function subscribe(staleTimeout, onHeight, onStatus, connect) {
|
|
|
58
58
|
closeConnectionRef.contents = undefined;
|
|
59
59
|
};
|
|
60
60
|
let armStaleTimeout = () => {
|
|
61
|
-
|
|
62
|
-
timeoutId.contents = Primitive_option.some(setTimeout(() => {
|
|
61
|
+
Clock.clearRef(clock, timeoutId);
|
|
62
|
+
timeoutId.contents = Primitive_option.some(clock.setTimeout("height stream stale", () => {
|
|
63
63
|
timeoutId.contents = undefined;
|
|
64
64
|
let detail = unreadableDetail.contents;
|
|
65
65
|
if (detail !== undefined) {
|
|
@@ -71,16 +71,16 @@ function subscribe(staleTimeout, onHeight, onStatus, connect) {
|
|
|
71
71
|
};
|
|
72
72
|
let fail = (reason, detail) => {
|
|
73
73
|
generation.contents = generation.contents + 1 | 0;
|
|
74
|
-
|
|
74
|
+
Clock.clearRef(clock, timeoutId);
|
|
75
75
|
closeConnection();
|
|
76
76
|
let since = liveAt.contents;
|
|
77
|
-
let servedMillis = since !== undefined ?
|
|
77
|
+
let servedMillis = since !== undefined ? clock.now() - since | 0 : 0;
|
|
78
78
|
let provenMillis = Primitive_int.max(retryDelayFor(failureCount.contents), minProvenMillis);
|
|
79
79
|
failureCount.contents = servedMillis >= provenMillis ? 1 : failureCount.contents + 1 | 0;
|
|
80
|
-
let retryMillis =
|
|
80
|
+
let retryMillis = Clock.jitter(clock, retryDelayFor(failureCount.contents));
|
|
81
81
|
let reason$1;
|
|
82
82
|
reason$1 = typeof reason !== "object" && reason === "Closed" && servedMillis >= provenMillis ? "Rotated" : reason;
|
|
83
|
-
timeoutId.contents = Primitive_option.some(setTimeout(() => {
|
|
83
|
+
timeoutId.contents = Primitive_option.some(clock.setTimeout("height stream retry", () => {
|
|
84
84
|
timeoutId.contents = undefined;
|
|
85
85
|
start();
|
|
86
86
|
}, retryMillis));
|
|
@@ -99,7 +99,7 @@ function subscribe(staleTimeout, onHeight, onStatus, connect) {
|
|
|
99
99
|
let goLive = () => {
|
|
100
100
|
armStaleTimeout();
|
|
101
101
|
if (Stdlib_Option.isNone(liveAt.contents)) {
|
|
102
|
-
liveAt.contents =
|
|
102
|
+
liveAt.contents = clock.now();
|
|
103
103
|
return onStatus("Live");
|
|
104
104
|
}
|
|
105
105
|
};
|
|
@@ -169,7 +169,7 @@ function subscribe(staleTimeout, onHeight, onStatus, connect) {
|
|
|
169
169
|
start();
|
|
170
170
|
return () => {
|
|
171
171
|
generation.contents = generation.contents + 1 | 0;
|
|
172
|
-
|
|
172
|
+
Clock.clearRef(clock, timeoutId);
|
|
173
173
|
closeConnection();
|
|
174
174
|
};
|
|
175
175
|
}
|
|
@@ -14,8 +14,8 @@ let failure = (error: EventSource.errorEvent): (
|
|
|
14
14
|
| (None, None) => (Closed, None)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
let subscribe = (~hyperSyncUrl, ~apiToken, ~onHeight, ~onStatus) =>
|
|
18
|
-
HeightStream.subscribe(~staleTimeout, ~onHeight, ~onStatus, ~connect=driver => {
|
|
17
|
+
let subscribe = (~clock, ~hyperSyncUrl, ~apiToken, ~onHeight, ~onStatus) =>
|
|
18
|
+
HeightStream.subscribe(~clock, ~staleTimeout, ~onHeight, ~onStatus, ~connect=driver => {
|
|
19
19
|
let userAgent = `hyperindex/${Utils.EnvioPackage.value.version}`
|
|
20
20
|
let es = EventSource.create(
|
|
21
21
|
~url=`${hyperSyncUrl}/height/sse`,
|
|
@@ -24,10 +24,8 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~onHeight, ~onStatus) =>
|
|
|
24
24
|
let headers =
|
|
25
25
|
args.headers
|
|
26
26
|
->Option.getOr(Dict.make())
|
|
27
|
-
->Utils.Dict.merge(
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
EventSource.Fetch.fetch(url, ~args={...args, headers: headers})
|
|
27
|
+
->Utils.Dict.merge(dict{"Authorization": `Bearer ${apiToken}`, "User-Agent": userAgent})
|
|
28
|
+
EventSource.Fetch.fetch(url, ~args={...args, headers})
|
|
31
29
|
},
|
|
32
30
|
},
|
|
33
31
|
)
|
|
@@ -30,8 +30,8 @@ function failure(error) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function subscribe(hyperSyncUrl, apiToken, onHeight, onStatus) {
|
|
34
|
-
return HeightStream.subscribe(15000, onHeight, onStatus, driver => {
|
|
33
|
+
function subscribe(clock, hyperSyncUrl, apiToken, onHeight, onStatus) {
|
|
34
|
+
return HeightStream.subscribe(clock, 15000, onHeight, onStatus, driver => {
|
|
35
35
|
let userAgent = `hyperindex/` + Utils.EnvioPackage.value.version;
|
|
36
36
|
let es = new Eventsource.EventSource(hyperSyncUrl + `/height/sse`, {
|
|
37
37
|
fetch: (url, args) => {
|
|
@@ -17,6 +17,10 @@ type options = {
|
|
|
17
17
|
transactionStore: TransactionStore.t,
|
|
18
18
|
ws?: string,
|
|
19
19
|
headers?: dict<string>,
|
|
20
|
+
// How many addresses one `eth_getLogs` may carry when an address-free query
|
|
21
|
+
// the provider couldn't answer is read again by address.
|
|
22
|
+
maxAddressesPerRequest: int,
|
|
23
|
+
logger: Logger.t,
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
let make = (
|
|
@@ -33,6 +37,8 @@ let make = (
|
|
|
33
37
|
transactionStore,
|
|
34
38
|
?ws,
|
|
35
39
|
?headers,
|
|
40
|
+
maxAddressesPerRequest,
|
|
41
|
+
logger,
|
|
36
42
|
}: options,
|
|
37
43
|
): t => {
|
|
38
44
|
let urlHost = switch Utils.Url.getHostFromUrl(url) {
|
|
@@ -53,6 +59,8 @@ let make = (
|
|
|
53
59
|
~syncConfig,
|
|
54
60
|
~headers?,
|
|
55
61
|
~addressStore,
|
|
62
|
+
~maxAddressesPerRequest,
|
|
63
|
+
~logger,
|
|
56
64
|
)
|
|
57
65
|
|
|
58
66
|
let getItemsOrThrow = async (
|
|
@@ -99,6 +107,7 @@ let make = (
|
|
|
99
107
|
clientFilteredContracts: selection.clientFilteredContracts,
|
|
100
108
|
retry,
|
|
101
109
|
?reorgableFrom,
|
|
110
|
+
knownHeight,
|
|
102
111
|
},
|
|
103
112
|
addressSet,
|
|
104
113
|
blockStore,
|
|
@@ -219,7 +228,7 @@ let make = (
|
|
|
219
228
|
|
|
220
229
|
let createHeightSubscription =
|
|
221
230
|
ws->Option.map(wsUrl =>
|
|
222
|
-
(~onHeight, ~onStatus) => EvmRpcWs.subscribe(~wsUrl, ~onHeight, ~onStatus)
|
|
231
|
+
(~clock, ~onHeight, ~onStatus) => EvmRpcWs.subscribe(~clock, ~wsUrl, ~onHeight, ~onStatus)
|
|
223
232
|
)
|
|
224
233
|
|
|
225
234
|
{
|
|
@@ -26,7 +26,7 @@ function make(param) {
|
|
|
26
26
|
let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` + ChainId.toString(chainId) + ` is in incorrect format. The RPC url needs to start with either http:// or https://`);
|
|
27
27
|
let name = `RPC (` + urlHost + `)`;
|
|
28
28
|
let onBlockRegistrations = Stdlib_Option.getOr(param.onBlockRegistrations, []);
|
|
29
|
-
let rpcClient = EvmRpcClient.make(url, !param.lowercaseAddresses, syncConfig, undefined, param.headers, HyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations), onBlockRegistrations, param.addressStore);
|
|
29
|
+
let rpcClient = EvmRpcClient.make(url, !param.lowercaseAddresses, syncConfig, undefined, param.headers, HyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations), onBlockRegistrations, param.addressStore, param.maxAddressesPerRequest, param.logger);
|
|
30
30
|
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, reorgableFrom, knownHeight, partitionId, selection, param, retry, param$1) => {
|
|
31
31
|
let totalTimeRef = Performance.now();
|
|
32
32
|
let toBlock$1 = toBlock !== undefined ? Primitive_int.min(toBlock, knownHeight) : knownHeight;
|
|
@@ -49,7 +49,8 @@ function make(param) {
|
|
|
49
49
|
onBlockRegistrationIndexes: selection.onBlockRegistrations.map(reg => reg.index),
|
|
50
50
|
clientFilteredContracts: selection.clientFilteredContracts,
|
|
51
51
|
retry: retry,
|
|
52
|
-
reorgableFrom: reorgableFrom
|
|
52
|
+
reorgableFrom: reorgableFrom,
|
|
53
|
+
knownHeight: knownHeight
|
|
53
54
|
}, addressSet, blockStore, transactionStore);
|
|
54
55
|
let result = match[0];
|
|
55
56
|
let pageFetchTime = Performance.secondsSince(pageFetchTimeRef);
|
|
@@ -148,7 +149,7 @@ function make(param) {
|
|
|
148
149
|
requestStats: result.requestStats
|
|
149
150
|
};
|
|
150
151
|
};
|
|
151
|
-
let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => ((onHeight, onStatus) => EvmRpcWs.subscribe(wsUrl, onHeight, onStatus)));
|
|
152
|
+
let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => ((clock, onHeight, onStatus) => EvmRpcWs.subscribe(clock, wsUrl, onHeight, onStatus)));
|
|
152
153
|
return {
|
|
153
154
|
name: name,
|
|
154
155
|
sourceFor: param.sourceFor,
|
package/src/sources/Source.res
CHANGED
|
@@ -240,6 +240,9 @@ type t = {
|
|
|
240
240
|
~logger: Logger.t,
|
|
241
241
|
) => promise<blockRangeFetchResponse>,
|
|
242
242
|
createHeightSubscription?: (
|
|
243
|
+
// The stream's staleness and reconnect timers run on the clock of the
|
|
244
|
+
// manager that subscribes, not one the source was built with.
|
|
245
|
+
~clock: Clock.t,
|
|
243
246
|
~onHeight: int => unit,
|
|
244
247
|
~onStatus: heightSubscriptionStatus => unit,
|
|
245
248
|
) => unit => unit,
|