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.
Files changed (186) hide show
  1. package/README.md +40 -34
  2. package/evm.schema.json +3 -3
  3. package/fuel.schema.json +2 -2
  4. package/index.d.ts +3 -3
  5. package/licenses/README.md +1 -1
  6. package/package.json +9 -10
  7. package/src/Batch.res.mjs +5 -5
  8. package/src/BatchProcessing.res +1 -0
  9. package/src/BatchProcessing.res.mjs +1 -0
  10. package/src/Bin.res +0 -7
  11. package/src/Bin.res.mjs +0 -8
  12. package/src/ChainFetching.res +17 -456
  13. package/src/ChainFetching.res.mjs +33 -404
  14. package/src/ChainState.res +48 -83
  15. package/src/ChainState.res.mjs +83 -115
  16. package/src/ChainState.resi +0 -26
  17. package/src/Clock.res +57 -0
  18. package/src/Clock.res.mjs +72 -0
  19. package/src/Config.res +7 -16
  20. package/src/Config.res.mjs +4 -11
  21. package/src/ContractRegisterContext.res +6 -3
  22. package/src/ContractRegisterContext.res.mjs +2 -4
  23. package/src/Core.res +5 -136
  24. package/src/Core.res.mjs +1 -90
  25. package/src/CrossChainState.res +2 -8
  26. package/src/CrossChainState.res.mjs +3 -3
  27. package/src/Ecosystem.res +4 -7
  28. package/src/Ecosystem.res.mjs +8 -8
  29. package/src/EffectState.res +10 -2
  30. package/src/EffectState.res.mjs +8 -4
  31. package/src/EffectState.resi +3 -1
  32. package/src/EntityId.res +2 -7
  33. package/src/EntityId.res.mjs +1 -8
  34. package/src/EntityTables.res +4 -1
  35. package/src/EntityTables.res.mjs +1 -1
  36. package/src/Env.res +0 -16
  37. package/src/Env.res.mjs +0 -11
  38. package/src/EventProcessing.res +1 -38
  39. package/src/EventProcessing.res.mjs +1 -28
  40. package/src/FetchState.res +160 -319
  41. package/src/FetchState.res.mjs +182 -292
  42. package/src/FinalizeBackfill.res +2 -4
  43. package/src/FinalizeBackfill.res.mjs +3 -4
  44. package/src/HandlerLoader.res +15 -39
  45. package/src/HandlerLoader.res.mjs +8 -27
  46. package/src/HandlerRegister.res +0 -4
  47. package/src/HandlerRegister.res.mjs +2 -5
  48. package/src/HandlerRegister.resi +0 -2
  49. package/src/InMemoryTable.res +17 -16
  50. package/src/InMemoryTable.res.mjs +14 -15
  51. package/src/IndexerState.res +28 -4
  52. package/src/IndexerState.res.mjs +19 -6
  53. package/src/IndexerState.resi +4 -0
  54. package/src/Internal.res +0 -110
  55. package/src/Internal.res.mjs +1 -115
  56. package/src/LoadLayer.res +21 -47
  57. package/src/LoadLayer.res.mjs +47 -72
  58. package/src/LoadLayer.resi +0 -26
  59. package/src/Main.res +1 -14
  60. package/src/Main.res.mjs +3 -4
  61. package/src/Persistence.res +3 -23
  62. package/src/Persistence.res.mjs +3 -3
  63. package/src/Rollback.res +0 -1
  64. package/src/Rollback.res.mjs +1 -1
  65. package/src/RunScope.res +0 -3
  66. package/src/SafeCheckpointTracking.res +4 -4
  67. package/src/SafeCheckpointTracking.res.mjs +1 -1
  68. package/src/SimulateItems.res +26 -42
  69. package/src/SimulateItems.res.mjs +16 -40
  70. package/src/StagedRows.res +106 -0
  71. package/src/StagedRows.res.mjs +102 -0
  72. package/src/Staging.res +32 -14
  73. package/src/Staging.res.mjs +17 -20
  74. package/src/Storage.res +277 -998
  75. package/src/Storage.res.mjs +216 -731
  76. package/src/Supervisor.res +75 -56
  77. package/src/Supervisor.res.mjs +55 -26
  78. package/src/TestIndexer.res +22 -27
  79. package/src/TestIndexer.res.mjs +20 -17
  80. package/src/Throttler.res +15 -8
  81. package/src/Throttler.res.mjs +9 -6
  82. package/src/Throttler.resi +1 -1
  83. package/src/UserContext.res +46 -410
  84. package/src/UserContext.res.mjs +30 -318
  85. package/src/Utils.res +0 -23
  86. package/src/Utils.res.mjs +1 -17
  87. package/src/Writing.res +0 -1
  88. package/src/Writing.res.mjs +1 -1
  89. package/src/bindings/ClickHouse.res +0 -322
  90. package/src/bindings/ClickHouse.res.mjs +0 -338
  91. package/src/bindings/StorageClient.res +107 -175
  92. package/src/bindings/StorageClient.res.mjs +19 -8
  93. package/src/bindings/Vitest.res +0 -26
  94. package/src/bindings/Vitest.res.mjs +0 -3
  95. package/src/db/Table.res +24 -150
  96. package/src/db/Table.res.mjs +38 -272
  97. package/src/sources/AddressSet.res +0 -2
  98. package/src/sources/AddressStore.res +0 -3
  99. package/src/sources/ChainSources.res +2 -0
  100. package/src/sources/ChainSources.res.mjs +2 -2
  101. package/src/sources/EvmChain.res +4 -7
  102. package/src/sources/EvmChain.res.mjs +5 -4
  103. package/src/sources/EvmHyperSyncSource.res +2 -2
  104. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  105. package/src/sources/EvmRpcClient.res +13 -3
  106. package/src/sources/EvmRpcClient.res.mjs +4 -3
  107. package/src/sources/EvmRpcWs.res +4 -3
  108. package/src/sources/EvmRpcWs.res.mjs +2 -2
  109. package/src/sources/HeightFeed.res +31 -10
  110. package/src/sources/HeightFeed.res.mjs +10 -6
  111. package/src/sources/HeightStream.res +32 -17
  112. package/src/sources/HeightStream.res.mjs +10 -10
  113. package/src/sources/HyperSync.res +1 -2
  114. package/src/sources/HyperSync.res.mjs +1 -2
  115. package/src/sources/HyperSyncSSE.res +4 -6
  116. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  117. package/src/sources/RpcSource.res +10 -1
  118. package/src/sources/RpcSource.res.mjs +4 -3
  119. package/src/sources/Source.res +3 -0
  120. package/src/sources/SourceManager.res +85 -104
  121. package/src/sources/SourceManager.res.mjs +18 -37
  122. package/src/sources/SourceManager.resi +3 -5
  123. package/src/sources/StartBlockResolver.res +1 -0
  124. package/src/sources/StartBlockResolver.res.mjs +4 -3
  125. package/src/sources/SvmHyperSyncSource.res +2 -2
  126. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  127. package/svm.schema.json +3 -3
  128. package/src/EffectCacheLookup.res +0 -98
  129. package/src/EffectCacheLookup.res.mjs +0 -116
  130. package/src/PgWriting.res +0 -36
  131. package/src/PgWriting.res.mjs +0 -34
  132. package/src/PreloadLookahead.res +0 -184
  133. package/src/PreloadLookahead.res.mjs +0 -197
  134. package/src/SubgraphLog.res +0 -19
  135. package/src/SubgraphLog.res.mjs +0 -26
  136. package/src/SyncWrites.res +0 -101
  137. package/src/SyncWrites.res.mjs +0 -98
  138. package/src/db/IndexDefinition.res +0 -47
  139. package/src/db/IndexDefinition.res.mjs +0 -60
  140. package/src/sources/CallSource.res +0 -274
  141. package/src/sources/CallSource.res.mjs +0 -196
  142. package/src/subgraph/abi-types.ts +0 -84
  143. package/src/subgraph/aggregations.ts +0 -745
  144. package/src/subgraph/as-package.ts +0 -143
  145. package/src/subgraph/assemblyscript-regex.ts +0 -67
  146. package/src/subgraph/assemblyscript.ts +0 -731
  147. package/src/subgraph/blocks.ts +0 -398
  148. package/src/subgraph/calls-source.ts +0 -702
  149. package/src/subgraph/calls.ts +0 -258
  150. package/src/subgraph/conformance.ts +0 -106
  151. package/src/subgraph/errors.ts +0 -85
  152. package/src/subgraph/graft.ts +0 -73
  153. package/src/subgraph/graph-cli-worker.mjs +0 -35
  154. package/src/subgraph/graph-cli.ts +0 -900
  155. package/src/subgraph/graph-node-decimal.ts +0 -199
  156. package/src/subgraph/graph-ts-enums.ts +0 -28
  157. package/src/subgraph/graph-ts-types/VERSION +0 -2
  158. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
  159. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
  160. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
  161. package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
  162. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
  163. package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
  164. package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
  165. package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
  166. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  167. package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
  168. package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
  169. package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
  170. package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
  171. package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
  172. package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
  173. package/src/subgraph/graph-ts-types/index.d.ts +0 -102
  174. package/src/subgraph/graph-ts.ts +0 -4280
  175. package/src/subgraph/hosts.ts +0 -554
  176. package/src/subgraph/log.ts +0 -28
  177. package/src/subgraph/receipts.ts +0 -184
  178. package/src/subgraph/register-slots.ts +0 -93
  179. package/src/subgraph/rollup.ts +0 -109
  180. package/src/subgraph/rpc.ts +0 -337
  181. package/src/subgraph/runtime.ts +0 -2060
  182. package/src/subgraph/scope.ts +0 -177
  183. package/src/subgraph/stats.ts +0 -42
  184. package/src/subgraph/template-instances.ts +0 -66
  185. package/src/subgraph/toolchain.ts +0 -327
  186. 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
- retryBackoffScale: float,
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
- // Wall-clock timestamp (Date.now()) when the current rate-limit window
97
- // started, or None if not currently waiting. Wall-clock so consumers
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
- // Wall-clock timestamp by which the server expects the longest current
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) => Date.now() -. 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 -. Date.now()
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 = Date.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 +. Date.now() -. startMs
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 Utils.delay(waitMs)
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
- retryBackoffScale: timing.retryBackoffScale->Option.getOr(1.),
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 = Date.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
- Utils.delay((millis->Int.toFloat *. sourceManager.retryBackoffScale)->Float.toInt)
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 = Date.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 waitForHeightAbove = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedPolling) => {
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
- pokeTimeoutId->Utils.clearTimeoutRef
855
- stallTimeoutId->Utils.clearTimeoutRef
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 = () => pokeTimeoutId := Some(setTimeout(() => {
926
- pokeTimeoutId := None
927
- if !settled.contents {
928
- watched->Array.forEach(subscription => subscription.distrustStream())
929
- }
930
-
931
- // Re-checked: distrusting can answer the wait, and a timer armed
932
- // after the cleanup that follows is one nothing can ever clear.
933
- if !settled.contents {
934
- armPokeTimeout()
935
- }
936
- }, Utils.jitter(stallTimeout)))
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 = () => stallTimeoutId := Some(setTimeout(() => {
943
- stallTimeoutId := None
944
- if !settled.contents {
945
- stalled := true
946
-
947
- // Build fallback: non-disabled sources not in mainSources with a valid role, even with recent lastFailedAt
948
- let fallbackSources = []
949
- sourcesState->Array.forEach(
950
- sourceState => {
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
- switch fallbackSources {
966
- | [] =>
967
- logger->Logger.warn(
968
- `No new blocks detected within ${(stallTimeout / 1000)
969
- ->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`,
970
- )
971
- | _ =>
972
- logger->Logger.warn(
973
- `No new blocks detected within ${(stallTimeout / 1000)
974
- ->Int.toString}s. Continuing polling with secondary RPC sources from the configuration.`,
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
- // A fallback recruited here can still be holding a stream from an
982
- // earlier wait that made it a primary, and a live stream is not
983
- // polled behind. It has to inherit the verdict the primaries
984
- // already earned — this wait has heard nothing for a whole window
985
- // — or it would sit silent behind that stream until the next
986
- // spread poke. Distrusting a waiter that already does so is a
987
- // no-op, so this reaches the new ones only.
988
- if !settled.contents {
989
- watched->Array.forEach(subscription => subscription.distrustStream())
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
- }, stallTimeout))
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 ? Date.now() - startMs : 0.0
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 - Date.now();
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 = Date.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 Utils.delay(waitMs);
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 + Date.now() - startMs;
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
- retryBackoffScale: Stdlib_Option.getOr(timing.retryBackoffScale, 1),
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 = Date.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 Utils.delay(millis * sourceManager.retryBackoffScale | 0);
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 = Date.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 waitForHeightAbove(sourceManager, knownHeight, isRealtime, reducedPolling) {
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
- Utils.clearTimeoutRef(pokeTimeoutId);
603
- Utils.clearTimeoutRef(stallTimeoutId);
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
- }, Utils.jitter(stallTimeout)));
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, undefined);
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
- /* Utils Not a pure module */
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": "The minimum number of new blocks the chain head must advance by before the indexer fetches again once it has caught up. Useful on chains with very fast blocks, where fetching every block is wasteful. Unset, 0 and 1 all fetch on every new block.",
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 code).",
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 HyperIndex generated code. Should be unique per program.",
360
+ "description": "Name of the instruction in the generated types. Should be unique per program.",
361
361
  "type": "string"
362
362
  },
363
363
  "discriminator": {