envio 3.15.0-subgraph → 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 +3 -3
- package/fuel.schema.json +2 -2
- package/index.d.ts +3 -3
- package/licenses/README.md +1 -1
- package/package.json +9 -10
- package/src/Batch.res.mjs +5 -5
- package/src/BatchProcessing.res +1 -0
- package/src/BatchProcessing.res.mjs +1 -0
- package/src/Bin.res +0 -7
- package/src/Bin.res.mjs +0 -8
- package/src/ChainFetching.res +17 -456
- package/src/ChainFetching.res.mjs +33 -404
- package/src/ChainState.res +48 -83
- package/src/ChainState.res.mjs +83 -115
- package/src/ChainState.resi +0 -26
- package/src/Clock.res +57 -0
- package/src/Clock.res.mjs +72 -0
- package/src/Config.res +7 -16
- package/src/Config.res.mjs +4 -11
- package/src/ContractRegisterContext.res +6 -3
- package/src/ContractRegisterContext.res.mjs +2 -4
- package/src/Core.res +5 -136
- package/src/Core.res.mjs +1 -90
- package/src/CrossChainState.res +2 -8
- package/src/CrossChainState.res.mjs +3 -3
- package/src/Ecosystem.res +4 -7
- package/src/Ecosystem.res.mjs +8 -8
- 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/Env.res +0 -16
- package/src/Env.res.mjs +0 -11
- package/src/EventProcessing.res +1 -38
- package/src/EventProcessing.res.mjs +1 -28
- package/src/FetchState.res +160 -319
- package/src/FetchState.res.mjs +182 -292
- package/src/FinalizeBackfill.res +2 -4
- package/src/FinalizeBackfill.res.mjs +3 -4
- package/src/HandlerLoader.res +15 -39
- package/src/HandlerLoader.res.mjs +8 -27
- package/src/HandlerRegister.res +0 -4
- package/src/HandlerRegister.res.mjs +2 -5
- package/src/HandlerRegister.resi +0 -2
- 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 -110
- package/src/Internal.res.mjs +1 -115
- package/src/LoadLayer.res +21 -47
- package/src/LoadLayer.res.mjs +47 -72
- package/src/LoadLayer.resi +0 -26
- package/src/Main.res +1 -14
- package/src/Main.res.mjs +3 -4
- 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/RunScope.res +0 -3
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +1 -1
- package/src/SimulateItems.res +26 -42
- package/src/SimulateItems.res.mjs +16 -40
- 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 -998
- package/src/Storage.res.mjs +216 -731
- 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/UserContext.res +46 -410
- package/src/UserContext.res.mjs +30 -318
- package/src/Utils.res +0 -23
- package/src/Utils.res.mjs +1 -17
- 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 -175
- 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/AddressSet.res +0 -2
- package/src/sources/AddressStore.res +0 -3
- package/src/sources/ChainSources.res +2 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +4 -7
- package/src/sources/EvmChain.res.mjs +5 -4
- 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/HyperSync.res +1 -2
- package/src/sources/HyperSync.res.mjs +1 -2
- 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 +85 -104
- package/src/sources/SourceManager.res.mjs +18 -37
- package/src/sources/SourceManager.resi +3 -5
- package/src/sources/StartBlockResolver.res +1 -0
- package/src/sources/StartBlockResolver.res.mjs +4 -3
- package/src/sources/SvmHyperSyncSource.res +2 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/svm.schema.json +3 -3
- package/src/EffectCacheLookup.res +0 -98
- package/src/EffectCacheLookup.res.mjs +0 -116
- package/src/PgWriting.res +0 -36
- package/src/PgWriting.res.mjs +0 -34
- package/src/PreloadLookahead.res +0 -184
- package/src/PreloadLookahead.res.mjs +0 -197
- package/src/SubgraphLog.res +0 -19
- package/src/SubgraphLog.res.mjs +0 -26
- package/src/SyncWrites.res +0 -101
- package/src/SyncWrites.res.mjs +0 -98
- package/src/db/IndexDefinition.res +0 -47
- package/src/db/IndexDefinition.res.mjs +0 -60
- package/src/sources/CallSource.res +0 -274
- package/src/sources/CallSource.res.mjs +0 -196
- package/src/subgraph/abi-types.ts +0 -84
- package/src/subgraph/aggregations.ts +0 -745
- package/src/subgraph/as-package.ts +0 -143
- package/src/subgraph/assemblyscript-regex.ts +0 -67
- package/src/subgraph/assemblyscript.ts +0 -731
- package/src/subgraph/blocks.ts +0 -398
- package/src/subgraph/calls-source.ts +0 -702
- package/src/subgraph/calls.ts +0 -258
- package/src/subgraph/conformance.ts +0 -106
- package/src/subgraph/errors.ts +0 -85
- package/src/subgraph/graft.ts +0 -73
- package/src/subgraph/graph-cli-worker.mjs +0 -35
- package/src/subgraph/graph-cli.ts +0 -900
- package/src/subgraph/graph-node-decimal.ts +0 -199
- package/src/subgraph/graph-ts-enums.ts +0 -28
- package/src/subgraph/graph-ts-types/VERSION +0 -2
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
- package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
- package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
- package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
- package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
- package/src/subgraph/graph-ts-types/index.d.ts +0 -102
- package/src/subgraph/graph-ts.ts +0 -4280
- package/src/subgraph/hosts.ts +0 -554
- package/src/subgraph/log.ts +0 -28
- package/src/subgraph/receipts.ts +0 -184
- package/src/subgraph/register-slots.ts +0 -93
- package/src/subgraph/rollup.ts +0 -109
- package/src/subgraph/rpc.ts +0 -337
- package/src/subgraph/runtime.ts +0 -2060
- package/src/subgraph/scope.ts +0 -177
- package/src/subgraph/stats.ts +0 -42
- package/src/subgraph/template-instances.ts +0 -66
- package/src/subgraph/toolchain.ts +0 -327
- package/src/subgraph/transient.ts +0 -176
|
@@ -85,7 +85,7 @@ type t = {
|
|
|
85
85
|
// Should take into consideration partitions fetching for previous states (before rollback)
|
|
86
86
|
mutable fetchingPartitionsCount: int,
|
|
87
87
|
recoveryTimeout: float,
|
|
88
|
-
|
|
88
|
+
clock: Clock.t,
|
|
89
89
|
// Why a source was last disabled for good. A disabled source is never
|
|
90
90
|
// retried, so by the time the manager runs out of sources this is the reason
|
|
91
91
|
// it did — and the only thing that tells a caller what to change.
|
|
@@ -93,11 +93,10 @@ type t = {
|
|
|
93
93
|
mutable hasRealtime: bool,
|
|
94
94
|
mutable committedRateLimitTimeMs: float,
|
|
95
95
|
mutable rateLimitWaiters: int,
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
// (TUI) can compute elapsed time with their own Date.now() reads.
|
|
96
|
+
// When the current rate-limit window started on `clock`, or None if not
|
|
97
|
+
// currently waiting.
|
|
99
98
|
mutable activeRateLimitStartMs: option<float>,
|
|
100
|
-
//
|
|
99
|
+
// Timestamp on `clock` by which the server expects the longest current
|
|
101
100
|
// wait to clear. Tracks the latest reset across concurrent waiters so
|
|
102
101
|
// the displayed countdown reflects when the indexer will actually retry.
|
|
103
102
|
mutable activeRateLimitResetAtMs: option<float>,
|
|
@@ -206,20 +205,20 @@ let inFlightCount = sourceManager => sourceManager.fetchingPartitionsCount
|
|
|
206
205
|
let getRateLimitTimeMs = sourceManager =>
|
|
207
206
|
sourceManager.committedRateLimitTimeMs +.
|
|
208
207
|
switch sourceManager.activeRateLimitStartMs {
|
|
209
|
-
| Some(startMs) =>
|
|
208
|
+
| Some(startMs) => sourceManager.clock.now() -. startMs
|
|
210
209
|
| None => 0.0
|
|
211
210
|
}
|
|
212
211
|
|
|
213
212
|
let getRateLimitResetInMs = sourceManager =>
|
|
214
213
|
switch sourceManager.activeRateLimitResetAtMs {
|
|
215
214
|
| Some(resetAt) =>
|
|
216
|
-
let remaining = resetAt -.
|
|
215
|
+
let remaining = resetAt -. sourceManager.clock.now()
|
|
217
216
|
remaining > 0.0 ? Some(remaining) : None
|
|
218
217
|
| None => None
|
|
219
218
|
}
|
|
220
219
|
|
|
221
220
|
let startRateLimitTimeout = (sourceManager, ~resetMs) => {
|
|
222
|
-
let now =
|
|
221
|
+
let now = sourceManager.clock.now()
|
|
223
222
|
if sourceManager.rateLimitWaiters === 0 {
|
|
224
223
|
sourceManager.activeRateLimitStartMs = Some(now)
|
|
225
224
|
}
|
|
@@ -237,7 +236,7 @@ let stopRateLimitTimeout = sourceManager => {
|
|
|
237
236
|
switch sourceManager.activeRateLimitStartMs {
|
|
238
237
|
| Some(startMs) =>
|
|
239
238
|
sourceManager.committedRateLimitTimeMs =
|
|
240
|
-
sourceManager.committedRateLimitTimeMs +.
|
|
239
|
+
sourceManager.committedRateLimitTimeMs +. sourceManager.clock.now() -. startMs
|
|
241
240
|
sourceManager.activeRateLimitStartMs = None
|
|
242
241
|
| None => ()
|
|
243
242
|
}
|
|
@@ -259,16 +258,8 @@ let waitForRateLimitReset = async (sourceManager: t, ~resetMs, ~retry, ~logger)
|
|
|
259
258
|
->Int.toString}s. For higher limits upgrade your plan at https://envio.dev/app/api-tokens.`,
|
|
260
259
|
~params={"retry": retry, "waitMs": waitMs},
|
|
261
260
|
)
|
|
262
|
-
let waitedAt = Date.now()
|
|
263
261
|
sourceManager->startRateLimitTimeout(~resetMs=waitMs)
|
|
264
|
-
await
|
|
265
|
-
// Timers run on the event loop's cached clock, so one can fire with Date.now()
|
|
266
|
-
// a millisecond short of the wait it was set for, and the wait is counted by
|
|
267
|
-
// Date.now(). Temporary until main takes the same fix.
|
|
268
|
-
let short = waitedAt +. waitMs->Int.toFloat -. Date.now()
|
|
269
|
-
if short > 0. {
|
|
270
|
-
await Utils.delay(short->Math.ceil->Float.toInt)
|
|
271
|
-
}
|
|
262
|
+
await sourceManager.clock->Clock.delay(~label="rate-limit reset", waitMs)
|
|
272
263
|
sourceManager->stopRateLimitTimeout
|
|
273
264
|
}
|
|
274
265
|
|
|
@@ -354,11 +345,12 @@ type timing = {
|
|
|
354
345
|
reducedPollingInterval?: int,
|
|
355
346
|
recoveryTimeout?: float,
|
|
356
347
|
getHeightRetryInterval?: (~retry: int) => int,
|
|
357
|
-
retryBackoffScale?: float,
|
|
358
348
|
heightPollTimeout?: int,
|
|
349
|
+
clock?: Clock.t,
|
|
359
350
|
}
|
|
360
351
|
|
|
361
352
|
let make = (~sources: array<Source.t>, ~logger: Logger.t, ~isRealtime, ~timing: timing={}) => {
|
|
353
|
+
let clock = timing.clock->Option.getOr(Clock.real)
|
|
362
354
|
let newBlockStallTimeout = timing.newBlockStallTimeout->Option.getOr(60_000)
|
|
363
355
|
let newBlockStallTimeoutRealtime = timing.newBlockStallTimeoutRealtime->Option.getOr(20_000)
|
|
364
356
|
let stalledPollingInterval = timing.stalledPollingInterval->Option.getOr(5_000)
|
|
@@ -392,6 +384,7 @@ let make = (~sources: array<Source.t>, ~logger: Logger.t, ~isRealtime, ~timing:
|
|
|
392
384
|
~recordRequestStats=stats => requestStats->recordStatsInto(stats),
|
|
393
385
|
~getHeightRetryInterval,
|
|
394
386
|
~pollTimeoutMillis=timing.heightPollTimeout->Option.getOr(60_000),
|
|
387
|
+
~clock,
|
|
395
388
|
),
|
|
396
389
|
disabled: false,
|
|
397
390
|
lastFailedAt: None,
|
|
@@ -408,7 +401,7 @@ let make = (~sources: array<Source.t>, ~logger: Logger.t, ~isRealtime, ~timing:
|
|
|
408
401
|
stalledPollingInterval,
|
|
409
402
|
reducedPollingInterval,
|
|
410
403
|
recoveryTimeout,
|
|
411
|
-
|
|
404
|
+
clock,
|
|
412
405
|
statusStart: Performance.now(),
|
|
413
406
|
status: Idle,
|
|
414
407
|
idleSeconds: 0.,
|
|
@@ -517,8 +510,8 @@ let compareByOldestFailure = (a: sourceState, b: sourceState) =>
|
|
|
517
510
|
}
|
|
518
511
|
|
|
519
512
|
// Priority: working primaries > working secondaries > all primaries.
|
|
520
|
-
let getNextSources = (sourceManager, ~isRealtime, ~excludedSources=?) => {
|
|
521
|
-
let now =
|
|
513
|
+
let getNextSources = (sourceManager: t, ~isRealtime, ~excludedSources=?) => {
|
|
514
|
+
let now = sourceManager.clock.now()
|
|
522
515
|
let workingPrimarySources = []
|
|
523
516
|
let allPrimarySources = []
|
|
524
517
|
let workingSecondarySources = []
|
|
@@ -589,10 +582,8 @@ let retryBackoffMillis = retry =>
|
|
|
589
582
|
// 0, these must never busy-loop when there is no other source to move to.
|
|
590
583
|
let minRecoverableBackoffMillis = 50
|
|
591
584
|
|
|
592
|
-
// The logged backoff stays the unscaled one, so a scaled-down test still reads
|
|
593
|
-
// the schedule an operator would see.
|
|
594
585
|
let sleepBackoff = (sourceManager: t, millis) =>
|
|
595
|
-
|
|
586
|
+
sourceManager.clock->Clock.delay(~label="retry backoff", millis)
|
|
596
587
|
|
|
597
588
|
// Back off before retrying the same request, failing the source over first when
|
|
598
589
|
// another one can actually take over. Marking `lastFailedAt` only demotes this
|
|
@@ -614,7 +605,7 @@ let backoffBeforeRetry = async (
|
|
|
614
605
|
let switchedToWorkingSource = if (
|
|
615
606
|
retry >= failoverAfterRetries && (retry - failoverAfterRetries)->mod(2) === 0
|
|
616
607
|
) {
|
|
617
|
-
let now =
|
|
608
|
+
let now = sourceManager.clock.now()
|
|
618
609
|
sourceState.lastFailedAt = Some(now)
|
|
619
610
|
switch sourceManager->getNextSource(~isRealtime, ~excludedSources?) {
|
|
620
611
|
| Some(next) =>
|
|
@@ -808,7 +799,7 @@ Resolves at the first height above `knownHeight` that any eligible source
|
|
|
808
799
|
reports. A waiter is registered per source and the first one to fire wins,
|
|
809
800
|
cancelling the rest.
|
|
810
801
|
*/
|
|
811
|
-
let
|
|
802
|
+
let waitForNewBlock = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedPolling) => {
|
|
812
803
|
let {sourcesState} = sourceManager
|
|
813
804
|
|
|
814
805
|
let logger = sourceManager.logger->Logger.withFields({
|
|
@@ -851,8 +842,8 @@ let waitForHeightAbove = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedP
|
|
|
851
842
|
let cleanup = () => {
|
|
852
843
|
watched->Array.forEach(subscription => subscription.unsubscribe())
|
|
853
844
|
watched->Utils.Array.clearInPlace
|
|
854
|
-
|
|
855
|
-
|
|
845
|
+
sourceManager.clock->Clock.clearRef(pokeTimeoutId)
|
|
846
|
+
sourceManager.clock->Clock.clearRef(stallTimeoutId)
|
|
856
847
|
}
|
|
857
848
|
|
|
858
849
|
let settled = ref(false)
|
|
@@ -922,32 +913,44 @@ let waitForHeightAbove = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedP
|
|
|
922
913
|
// Re-armed because distrusting a stream is a one-shot — the next height it
|
|
923
914
|
// delivers takes it back at its word — and the silence that earned it can
|
|
924
915
|
// come straight back.
|
|
925
|
-
let rec armPokeTimeout = () =>
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
916
|
+
let rec armPokeTimeout = () =>
|
|
917
|
+
pokeTimeoutId :=
|
|
918
|
+
Some(
|
|
919
|
+
sourceManager.clock.setTimeout(
|
|
920
|
+
~label="stall poke",
|
|
921
|
+
() => {
|
|
922
|
+
pokeTimeoutId := None
|
|
923
|
+
if !settled.contents {
|
|
924
|
+
watched->Array.forEach(subscription => subscription.distrustStream())
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// Re-checked: distrusting can answer the wait, and a timer armed
|
|
928
|
+
// after the cleanup that follows is one nothing can ever clear.
|
|
929
|
+
if !settled.contents {
|
|
930
|
+
armPokeTimeout()
|
|
931
|
+
}
|
|
932
|
+
},
|
|
933
|
+
sourceManager.clock->Clock.jitter(stallTimeout),
|
|
934
|
+
),
|
|
935
|
+
)
|
|
937
936
|
|
|
938
937
|
// Punctual, unlike the poke above: newBlockStallTimeout is a promise to the
|
|
939
938
|
// operator about when they hear about a quiet chain, and spreading that
|
|
940
939
|
// would report it early. Fires once — the warning is worth saying once per
|
|
941
940
|
// wait, and a fallback stays recruited.
|
|
942
|
-
let armStallTimeout = () =>
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
941
|
+
let armStallTimeout = () =>
|
|
942
|
+
stallTimeoutId :=
|
|
943
|
+
Some(
|
|
944
|
+
sourceManager.clock.setTimeout(
|
|
945
|
+
~label="stall timeout",
|
|
946
|
+
() => {
|
|
947
|
+
stallTimeoutId := None
|
|
948
|
+
if !settled.contents {
|
|
949
|
+
stalled := true
|
|
950
|
+
|
|
951
|
+
// Build fallback: non-disabled sources not in mainSources with a valid role, even with recent lastFailedAt
|
|
952
|
+
let fallbackSources = []
|
|
953
|
+
sourcesState->Array.forEach(sourceState => {
|
|
951
954
|
if (
|
|
952
955
|
!sourceState.disabled &&
|
|
953
956
|
!(mainSources->Array.includes(sourceState)) &&
|
|
@@ -959,37 +962,41 @@ let waitForHeightAbove = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedP
|
|
|
959
962
|
) {
|
|
960
963
|
fallbackSources->Array.push(sourceState)
|
|
961
964
|
}
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
965
|
+
})
|
|
966
|
+
|
|
967
|
+
switch fallbackSources {
|
|
968
|
+
| [] =>
|
|
969
|
+
logger->Logger.warn(
|
|
970
|
+
`No new blocks detected within ${(stallTimeout / 1000)
|
|
971
|
+
->Int.toString}s. Polling will continue at a reduced rate. For better reliability, refer to our RPC fallback guide: https://docs.envio.dev/docs/HyperIndex/rpc-sync`,
|
|
972
|
+
)
|
|
973
|
+
| _ =>
|
|
974
|
+
logger->Logger.warn(
|
|
975
|
+
`No new blocks detected within ${(stallTimeout / 1000)
|
|
976
|
+
->Int.toString}s. Continuing polling with secondary RPC sources from the configuration.`,
|
|
977
|
+
)
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// Recruited to poll, not to stream: see `watch`.
|
|
981
|
+
fallbackSources->Array.forEach(sourceState =>
|
|
982
|
+
sourceState->watch(~withStream=false)
|
|
975
983
|
)
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// Recruited to poll, not to stream: see `watch`.
|
|
979
|
-
fallbackSources->Array.forEach(sourceState => sourceState->watch(~withStream=false))
|
|
980
984
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
985
|
+
// A fallback recruited here can still be holding a stream from an
|
|
986
|
+
// earlier wait that made it a primary, and a live stream is not
|
|
987
|
+
// polled behind. It has to inherit the verdict the primaries
|
|
988
|
+
// already earned — this wait has heard nothing for a whole window
|
|
989
|
+
// — or it would sit silent behind that stream until the next
|
|
990
|
+
// spread poke. Distrusting a waiter that already does so is a
|
|
991
|
+
// no-op, so this reaches the new ones only.
|
|
992
|
+
if !settled.contents {
|
|
993
|
+
watched->Array.forEach(subscription => subscription.distrustStream())
|
|
994
|
+
}
|
|
990
995
|
}
|
|
991
|
-
}
|
|
992
|
-
|
|
996
|
+
},
|
|
997
|
+
stallTimeout,
|
|
998
|
+
),
|
|
999
|
+
)
|
|
993
1000
|
|
|
994
1001
|
armPokeTimeout()
|
|
995
1002
|
armStallTimeout()
|
|
@@ -997,32 +1004,6 @@ let waitForHeightAbove = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedP
|
|
|
997
1004
|
})
|
|
998
1005
|
}
|
|
999
1006
|
|
|
1000
|
-
// Waits block by block rather than for the far height directly, so each block
|
|
1001
|
-
// restarts the stall window and only a head that really went quiet reports a
|
|
1002
|
-
// stall. A chain with no known height takes its first one as is: a head below
|
|
1003
|
-
// `blockThrottle` would otherwise never start fetching.
|
|
1004
|
-
let waitForNewBlock = (
|
|
1005
|
-
sourceManager: t,
|
|
1006
|
-
~knownHeight,
|
|
1007
|
-
~isRealtime,
|
|
1008
|
-
~reducedPolling,
|
|
1009
|
-
~blockThrottle=0,
|
|
1010
|
-
) => {
|
|
1011
|
-
if knownHeight === 0 || blockThrottle <= 1 {
|
|
1012
|
-
sourceManager->waitForHeightAbove(~knownHeight, ~isRealtime, ~reducedPolling)
|
|
1013
|
-
} else {
|
|
1014
|
-
let rec waitAbove = async height => {
|
|
1015
|
-
let newHeight = await sourceManager->waitForHeightAbove(
|
|
1016
|
-
~knownHeight=height,
|
|
1017
|
-
~isRealtime,
|
|
1018
|
-
~reducedPolling,
|
|
1019
|
-
)
|
|
1020
|
-
newHeight < knownHeight + blockThrottle ? await waitAbove(newHeight) : newHeight
|
|
1021
|
-
}
|
|
1022
|
-
waitAbove(knownHeight)
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
1007
|
let executeQuery = async (
|
|
1027
1008
|
sourceManager: t,
|
|
1028
1009
|
~query: FetchState.query,
|
|
@@ -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";
|
|
@@ -153,7 +154,7 @@ function inFlightCount(sourceManager) {
|
|
|
153
154
|
function getRateLimitTimeMs(sourceManager) {
|
|
154
155
|
let startMs = sourceManager.activeRateLimitStartMs;
|
|
155
156
|
return sourceManager.committedRateLimitTimeMs + (
|
|
156
|
-
startMs !== undefined ?
|
|
157
|
+
startMs !== undefined ? sourceManager.clock.now() - startMs : 0.0
|
|
157
158
|
);
|
|
158
159
|
}
|
|
159
160
|
|
|
@@ -162,14 +163,14 @@ function getRateLimitResetInMs(sourceManager) {
|
|
|
162
163
|
if (resetAt === undefined) {
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
165
|
-
let remaining = resetAt -
|
|
166
|
+
let remaining = resetAt - sourceManager.clock.now();
|
|
166
167
|
if (remaining > 0.0) {
|
|
167
168
|
return remaining;
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
function startRateLimitTimeout(sourceManager, resetMs) {
|
|
172
|
-
let now =
|
|
173
|
+
let now = sourceManager.clock.now();
|
|
173
174
|
if (sourceManager.rateLimitWaiters === 0) {
|
|
174
175
|
sourceManager.activeRateLimitStartMs = now;
|
|
175
176
|
}
|
|
@@ -186,20 +187,15 @@ async function waitForRateLimitReset(sourceManager, resetMs, retry, logger) {
|
|
|
186
187
|
retry: retry,
|
|
187
188
|
waitMs: waitMs
|
|
188
189
|
});
|
|
189
|
-
let waitedAt = Date.now();
|
|
190
190
|
startRateLimitTimeout(sourceManager, waitMs);
|
|
191
|
-
await
|
|
192
|
-
let short = waitedAt + waitMs - Date.now();
|
|
193
|
-
if (short > 0) {
|
|
194
|
-
await Utils.delay(Math.ceil(short) | 0);
|
|
195
|
-
}
|
|
191
|
+
await Clock.delay(sourceManager.clock, "rate-limit reset", waitMs);
|
|
196
192
|
sourceManager.rateLimitWaiters = sourceManager.rateLimitWaiters - 1 | 0;
|
|
197
193
|
if (sourceManager.rateLimitWaiters !== 0) {
|
|
198
194
|
return;
|
|
199
195
|
}
|
|
200
196
|
let startMs = sourceManager.activeRateLimitStartMs;
|
|
201
197
|
if (startMs !== undefined) {
|
|
202
|
-
sourceManager.committedRateLimitTimeMs = sourceManager.committedRateLimitTimeMs +
|
|
198
|
+
sourceManager.committedRateLimitTimeMs = sourceManager.committedRateLimitTimeMs + sourceManager.clock.now() - startMs;
|
|
203
199
|
sourceManager.activeRateLimitStartMs = undefined;
|
|
204
200
|
}
|
|
205
201
|
sourceManager.activeRateLimitResetAtMs = undefined;
|
|
@@ -278,6 +274,7 @@ function makeGetHeightRetryInterval(initialRetryInterval, backoffMultiplicative,
|
|
|
278
274
|
|
|
279
275
|
function make(sources, logger, isRealtime, timingOpt) {
|
|
280
276
|
let timing = timingOpt !== undefined ? timingOpt : ({});
|
|
277
|
+
let clock = Stdlib_Option.getOr(timing.clock, Clock.real);
|
|
281
278
|
let newBlockStallTimeout = Stdlib_Option.getOr(timing.newBlockStallTimeout, 60000);
|
|
282
279
|
let newBlockStallTimeoutRealtime = Stdlib_Option.getOr(timing.newBlockStallTimeoutRealtime, 20000);
|
|
283
280
|
let stalledPollingInterval = Stdlib_Option.getOr(timing.stalledPollingInterval, 5000);
|
|
@@ -293,7 +290,7 @@ function make(sources, logger, isRealtime, timingOpt) {
|
|
|
293
290
|
let requestStats = {};
|
|
294
291
|
return {
|
|
295
292
|
source: source,
|
|
296
|
-
feed: HeightFeed.make(source, logger, stats => recordStatsInto(requestStats, stats), getHeightRetryInterval$1, Stdlib_Option.getOr(timing.heightPollTimeout, 60000)),
|
|
293
|
+
feed: HeightFeed.make(source, logger, stats => recordStatsInto(requestStats, stats), getHeightRetryInterval$1, Stdlib_Option.getOr(timing.heightPollTimeout, 60000), clock),
|
|
297
294
|
disabled: false,
|
|
298
295
|
lastFailedAt: undefined,
|
|
299
296
|
requestStats: requestStats
|
|
@@ -314,7 +311,7 @@ function make(sources, logger, isRealtime, timingOpt) {
|
|
|
314
311
|
waitingLogged: false,
|
|
315
312
|
fetchingPartitionsCount: 0,
|
|
316
313
|
recoveryTimeout: recoveryTimeout,
|
|
317
|
-
|
|
314
|
+
clock: clock,
|
|
318
315
|
disableReason: undefined,
|
|
319
316
|
hasRealtime: hasRealtime,
|
|
320
317
|
committedRateLimitTimeMs: 0.0,
|
|
@@ -422,7 +419,7 @@ function compareByOldestFailure(a, b) {
|
|
|
422
419
|
}
|
|
423
420
|
|
|
424
421
|
function getNextSources(sourceManager, isRealtime, excludedSources) {
|
|
425
|
-
let now =
|
|
422
|
+
let now = sourceManager.clock.now();
|
|
426
423
|
let workingPrimarySources = [];
|
|
427
424
|
let allPrimarySources = [];
|
|
428
425
|
let workingSecondarySources = [];
|
|
@@ -475,7 +472,7 @@ function getNextSource(sourceManager, isRealtime, excludedSources) {
|
|
|
475
472
|
}
|
|
476
473
|
|
|
477
474
|
function sleepBackoff(sourceManager, millis) {
|
|
478
|
-
return
|
|
475
|
+
return Clock.delay(sourceManager.clock, "retry backoff", millis);
|
|
479
476
|
}
|
|
480
477
|
|
|
481
478
|
async function backoffBeforeRetry(sourceManager, sourceState, retry, isRealtime, backoffMillis, minBackoffMillisOpt, failoverAfterRetriesOpt, excludedSources) {
|
|
@@ -483,7 +480,7 @@ async function backoffBeforeRetry(sourceManager, sourceState, retry, isRealtime,
|
|
|
483
480
|
let failoverAfterRetries = failoverAfterRetriesOpt !== undefined ? failoverAfterRetriesOpt : 2;
|
|
484
481
|
let switchedToWorkingSource;
|
|
485
482
|
if (retry >= failoverAfterRetries && (retry - failoverAfterRetries | 0) % 2 === 0) {
|
|
486
|
-
let now =
|
|
483
|
+
let now = sourceManager.clock.now();
|
|
487
484
|
sourceState.lastFailedAt = now;
|
|
488
485
|
let next = getNextSource(sourceManager, isRealtime, excludedSources);
|
|
489
486
|
if (next !== undefined) {
|
|
@@ -572,7 +569,7 @@ async function retryFailedPage(sourceManager, sourceState, retry, isRealtime, lo
|
|
|
572
569
|
return await backoffBeforeRetry(sourceManager, sourceState, retry, isRealtime, backoffMillis, minBackoffMillis, undefined, excludedSources);
|
|
573
570
|
}
|
|
574
571
|
|
|
575
|
-
function
|
|
572
|
+
function waitForNewBlock(sourceManager, knownHeight, isRealtime, reducedPolling) {
|
|
576
573
|
let sourcesState = sourceManager.sourcesState;
|
|
577
574
|
let logger = Logger.withFields(sourceManager.logger, {
|
|
578
575
|
knownHeight: knownHeight
|
|
@@ -599,8 +596,8 @@ function waitForHeightAbove(sourceManager, knownHeight, isRealtime, reducedPolli
|
|
|
599
596
|
let cleanup = () => {
|
|
600
597
|
watched.forEach(subscription => subscription.unsubscribe());
|
|
601
598
|
Utils.$$Array.clearInPlace(watched);
|
|
602
|
-
|
|
603
|
-
|
|
599
|
+
Clock.clearRef(sourceManager.clock, pokeTimeoutId);
|
|
600
|
+
Clock.clearRef(sourceManager.clock, stallTimeoutId);
|
|
604
601
|
};
|
|
605
602
|
let settled = {
|
|
606
603
|
contents: false
|
|
@@ -648,7 +645,7 @@ function waitForHeightAbove(sourceManager, knownHeight, isRealtime, reducedPolli
|
|
|
648
645
|
return;
|
|
649
646
|
}
|
|
650
647
|
let armPokeTimeout = () => {
|
|
651
|
-
pokeTimeoutId.contents = Primitive_option.some(setTimeout(() => {
|
|
648
|
+
pokeTimeoutId.contents = Primitive_option.some(sourceManager.clock.setTimeout("stall poke", () => {
|
|
652
649
|
pokeTimeoutId.contents = undefined;
|
|
653
650
|
if (!settled.contents) {
|
|
654
651
|
watched.forEach(subscription => subscription.distrustStream());
|
|
@@ -656,10 +653,10 @@ function waitForHeightAbove(sourceManager, knownHeight, isRealtime, reducedPolli
|
|
|
656
653
|
if (!settled.contents) {
|
|
657
654
|
return armPokeTimeout();
|
|
658
655
|
}
|
|
659
|
-
},
|
|
656
|
+
}, Clock.jitter(sourceManager.clock, stallTimeout)));
|
|
660
657
|
};
|
|
661
658
|
let armStallTimeout = () => {
|
|
662
|
-
stallTimeoutId.contents = Primitive_option.some(setTimeout(() => {
|
|
659
|
+
stallTimeoutId.contents = Primitive_option.some(sourceManager.clock.setTimeout("stall timeout", () => {
|
|
663
660
|
stallTimeoutId.contents = undefined;
|
|
664
661
|
if (settled.contents) {
|
|
665
662
|
return;
|
|
@@ -689,22 +686,6 @@ function waitForHeightAbove(sourceManager, knownHeight, isRealtime, reducedPolli
|
|
|
689
686
|
});
|
|
690
687
|
}
|
|
691
688
|
|
|
692
|
-
function waitForNewBlock(sourceManager, knownHeight, isRealtime, reducedPolling, blockThrottleOpt) {
|
|
693
|
-
let blockThrottle = blockThrottleOpt !== undefined ? blockThrottleOpt : 0;
|
|
694
|
-
if (knownHeight === 0 || blockThrottle <= 1) {
|
|
695
|
-
return waitForHeightAbove(sourceManager, knownHeight, isRealtime, reducedPolling);
|
|
696
|
-
}
|
|
697
|
-
let waitAbove = async height => {
|
|
698
|
-
let newHeight = await waitForHeightAbove(sourceManager, height, isRealtime, reducedPolling);
|
|
699
|
-
if (newHeight < (knownHeight + blockThrottle | 0)) {
|
|
700
|
-
return await waitAbove(newHeight);
|
|
701
|
-
} else {
|
|
702
|
-
return newHeight;
|
|
703
|
-
}
|
|
704
|
-
};
|
|
705
|
-
return waitAbove(knownHeight);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
689
|
async function executeQuery(sourceManager, query, knownHeight, isRealtime, reorgableFrom) {
|
|
709
690
|
let noSourcesError = () => {
|
|
710
691
|
let reason = sourceManager.disableReason;
|
|
@@ -17,11 +17,10 @@ type timing = {
|
|
|
17
17
|
reducedPollingInterval?: int,
|
|
18
18
|
recoveryTimeout?: float,
|
|
19
19
|
getHeightRetryInterval?: (~retry: int) => int,
|
|
20
|
-
// Multiplies the sleep before retrying an items query or a block-hash
|
|
21
|
-
// lookup, but not the backoff it logs. A rate limit's wait is the server's
|
|
22
|
-
// to set and isn't scaled.
|
|
23
|
-
retryBackoffScale?: float,
|
|
24
20
|
heightPollTimeout?: int,
|
|
21
|
+
// Every timer the manager and its height feeds arm, and every time they
|
|
22
|
+
// read. A test passes one that only moves when the test advances it.
|
|
23
|
+
clock?: Clock.t,
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
let make: (~sources: array<Source.t>, ~logger: Logger.t, ~isRealtime: bool, ~timing: timing=?) => t
|
|
@@ -79,7 +78,6 @@ let waitForNewBlock: (
|
|
|
79
78
|
~knownHeight: int,
|
|
80
79
|
~isRealtime: bool,
|
|
81
80
|
~reducedPolling: bool,
|
|
82
|
-
~blockThrottle: int=?,
|
|
83
81
|
) => promise<int>
|
|
84
82
|
|
|
85
83
|
// The retry at which a query that no source can answer stops being a hiccup
|
|
@@ -25,6 +25,7 @@ let makeProbeSources = (chainConfig: Config.chain, ~logger, ~lowercaseAddresses)
|
|
|
25
25
|
~blockStore=BlockStore.make(~ecosystem=chainConfig.ecosystem),
|
|
26
26
|
~transactionStore=TransactionStore.make(~ecosystem=chainConfig.ecosystem),
|
|
27
27
|
~logger,
|
|
28
|
+
~maxAddressesPerRequest=Env.maxAddrInPartition,
|
|
28
29
|
)
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Env from "../Env.res.mjs";
|
|
3
4
|
import * as Utils from "../Utils.res.mjs";
|
|
4
5
|
import * as Logger from "../Logger.res.mjs";
|
|
5
6
|
import * as ChainId from "../ChainId.res.mjs";
|
|
@@ -14,7 +15,7 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
|
|
|
14
15
|
|
|
15
16
|
function makeProbeSources(chainConfig, logger, lowercaseAddresses) {
|
|
16
17
|
let addressStore = AddressStore.make(chainConfig.ecosystem, []);
|
|
17
|
-
return ChainSources.make(chainConfig, [], undefined, addressStore, lowercaseAddresses, BlockStore.make(chainConfig.ecosystem), TransactionStore.make(chainConfig.ecosystem), logger);
|
|
18
|
+
return ChainSources.make(chainConfig, [], undefined, addressStore, lowercaseAddresses, BlockStore.make(chainConfig.ecosystem), TransactionStore.make(chainConfig.ecosystem), logger, Env.maxAddrInPartition);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
function candidateSources(sources) {
|
|
@@ -87,7 +88,7 @@ async function resolveHeadOrThrow(chainConfig, logger, lowercaseAddresses, retry
|
|
|
87
88
|
return await readHeadOnceOrThrow(chainConfig, sources);
|
|
88
89
|
}
|
|
89
90
|
let sourceManager = SourceManager.make(sources, logger, false, timing);
|
|
90
|
-
return await SourceManager.waitForNewBlock(sourceManager, 0, false, false
|
|
91
|
+
return await SourceManager.waitForNewBlock(sourceManager, 0, false, false);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
async function resolveAllOrThrow(chainConfigs, logger, lowercaseAddresses, retryOpt, timing) {
|
|
@@ -132,4 +133,4 @@ export {
|
|
|
132
133
|
resolveHeadOrThrow,
|
|
133
134
|
resolveAllOrThrow,
|
|
134
135
|
}
|
|
135
|
-
/*
|
|
136
|
+
/* Env Not a pure module */
|
|
@@ -277,7 +277,7 @@ let make = (
|
|
|
277
277
|
{height, requestStats: [{method: "getHeight", seconds}]}
|
|
278
278
|
},
|
|
279
279
|
getItemsOrThrow,
|
|
280
|
-
createHeightSubscription: (~onHeight, ~onStatus) =>
|
|
281
|
-
HyperSyncSSE.subscribe(~hyperSyncUrl=endpointUrl, ~apiToken, ~onHeight, ~onStatus),
|
|
280
|
+
createHeightSubscription: (~clock, ~onHeight, ~onStatus) =>
|
|
281
|
+
HyperSyncSSE.subscribe(~clock, ~hyperSyncUrl=endpointUrl, ~apiToken, ~onHeight, ~onStatus),
|
|
282
282
|
}
|
|
283
283
|
}
|
|
@@ -205,7 +205,7 @@ function make(param) {
|
|
|
205
205
|
};
|
|
206
206
|
},
|
|
207
207
|
getItemsOrThrow: getItemsOrThrow,
|
|
208
|
-
createHeightSubscription: (onHeight, onStatus) => HyperSyncSSE.subscribe(endpointUrl, apiToken, onHeight, onStatus)
|
|
208
|
+
createHeightSubscription: (clock, onHeight, onStatus) => HyperSyncSSE.subscribe(clock, endpointUrl, apiToken, onHeight, onStatus)
|
|
209
209
|
};
|
|
210
210
|
}
|
|
211
211
|
|
package/svm.schema.json
CHANGED
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
"minimum": 0
|
|
221
221
|
},
|
|
222
222
|
"block_throttle": {
|
|
223
|
-
"description": "
|
|
223
|
+
"description": "Once caught up, wait for this many new slots before fetching them. Delays new instructions by up to as many slots.",
|
|
224
224
|
"type": [
|
|
225
225
|
"integer",
|
|
226
226
|
"null"
|
|
@@ -303,7 +303,7 @@
|
|
|
303
303
|
"type": "object",
|
|
304
304
|
"properties": {
|
|
305
305
|
"name": {
|
|
306
|
-
"description": "A unique project-wide name for this program (used in generated
|
|
306
|
+
"description": "A unique project-wide name for this program (used in the generated types).",
|
|
307
307
|
"type": "string"
|
|
308
308
|
},
|
|
309
309
|
"program_id": {
|
|
@@ -357,7 +357,7 @@
|
|
|
357
357
|
"type": "object",
|
|
358
358
|
"properties": {
|
|
359
359
|
"name": {
|
|
360
|
-
"description": "Name of the instruction in the
|
|
360
|
+
"description": "Name of the instruction in the generated types. Should be unique per program.",
|
|
361
361
|
"type": "string"
|
|
362
362
|
},
|
|
363
363
|
"discriminator": {
|