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
@@ -26,9 +26,6 @@ type t = {
26
26
  // scheduler doesn't re-sum pending queries on every tick. Incremented when
27
27
  // queries are dispatched, decremented as their responses land.
28
28
  mutable pendingBudget: float,
29
- // Counts resets of pendingBudget: a hold taken before one has nothing left
30
- // to release.
31
- mutable pendingBudgetResets: int,
32
29
  // Chain-wide events/block, used to turn a chain's item budget into a target
33
30
  // block for query sizing. Seeded from cumulative progress on construction,
34
31
  // then smoothed with an EMA on every batch (see applyBatchProgress). None
@@ -76,12 +73,6 @@ type t = {
76
73
  // Timestamp of the committed progress block itself. See
77
74
  // `Batch.chainAfterBatch.progressBlockTime`.
78
75
  mutable committedProgressBlockTime: option<int>,
79
- // Subgraph mode, with a block handler that has a register pass: the chain's
80
- // register work runs one unit at a time, a response's passes or a run of
81
- // block passes alone, so a pass never runs ahead of a block pass of an
82
- // earlier block. Settles when the latest unit is applied.
83
- mutable blockRegisterTail: promise<unit>,
84
- mutable blockRegisterRuns: int,
85
76
  }
86
77
 
87
78
  // The chain's config-declared addresses as storage rows: what a clean run
@@ -176,7 +167,6 @@ let make = (
176
167
  processingBlockNumber: committedProgressBlockNumber,
177
168
  numEventsProcessed,
178
169
  pendingBudget: 0.,
179
- pendingBudgetResets: 0,
180
170
  chainDensity,
181
171
  safeCheckpointTracking,
182
172
  shouldRollbackOnReorg,
@@ -197,8 +187,6 @@ let make = (
197
187
  rollbackTargetBlock: None,
198
188
  progressLatencyMs: None,
199
189
  committedProgressBlockTime,
200
- blockRegisterTail: Promise.resolve(),
201
- blockRegisterRuns: 0,
202
190
  }
203
191
  }
204
192
 
@@ -320,14 +308,18 @@ let makeInternal = (
320
308
  // FIXME: Shouldn't set with full history
321
309
  // The resumed depth, not the config one: the pre-threshold lag must match
322
310
  // the window reorg detection compares, or a reduced config depth would let
323
- // fetching enter the stored rollback window without history.
311
+ // fetching enter the stored rollback window without history. One block
312
+ // more than the window, so the last pre-threshold page ends below it and
313
+ // the window's first block is read by a page that knows it is reorgable.
324
314
  ~blockLag=Pervasives.max(
325
- !config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : maxReorgDepth,
315
+ !config.shouldRollbackOnReorg || isInReorgThreshold || maxReorgDepth == 0
316
+ ? 0
317
+ : maxReorgDepth + 1,
326
318
  chainConfig.blockLag,
327
319
  ),
320
+ ~blockThrottle=chainConfig.blockThrottle,
328
321
  ~onBlockRegistrations,
329
322
  ~firstEventBlock,
330
- ~deferCreationBlockEvents=config.subgraph->Option.isSome,
331
323
  // Fuel and SVM route through the address store like EVM does, so the
332
324
  // client-side path works for them - but their address counts are nowhere
333
325
  // near the threshold, so switching would only trade a server-side filter
@@ -362,6 +354,7 @@ let makeInternal = (
362
354
  ~blockStore,
363
355
  ~transactionStore,
364
356
  ~logger,
357
+ ~maxAddressesPerRequest=config.maxAddrInPartition,
365
358
  )
366
359
 
367
360
  // Seed the stored reorg checkpoints (hash-only rows) so detection resumes
@@ -472,7 +465,6 @@ let logger = (cs: t) => cs.logger
472
465
  let blockStore = (cs: t) => cs.blockStore
473
466
  let transactionStore = (cs: t) => cs.transactionStore
474
467
  let shouldChecksum = (cs: t) => cs.shouldChecksum
475
- let fetchState = (cs: t) => cs.fetchState
476
468
  let entities = (cs: t) => cs.entities
477
469
 
478
470
  // Rollback discards every uncommitted change, so this chain's partition is
@@ -559,70 +551,8 @@ let startFetchingQueries = (cs: t, ~queries: array<FetchState.query>) => {
559
551
  let resetPendingQueries = (cs: t) => {
560
552
  cs.fetchState = cs.fetchState->FetchState.resetPendingQueries
561
553
  cs.pendingBudget = 0.
562
- cs.pendingBudgetResets = cs.pendingBudgetResets + 1
563
554
  }
564
555
 
565
- // A response that landed with more items than its query was priced at keeps the
566
- // excess reserved while it waits for its register passes: until then its items
567
- // are neither in the buffer nor in the query's estimate, and the pool would
568
- // admit the next queries on top of them. Released when the response is applied.
569
- type heldBudget = {items: int, resets: int}
570
-
571
- let holdExtraBudget = (cs: t, ~items) => {
572
- cs.pendingBudget = cs.pendingBudget +. items->Int.toFloat
573
- {items, resets: cs.pendingBudgetResets}
574
- }
575
-
576
- let releaseExtraBudget = (cs: t, held: heldBudget) =>
577
- if held.resets === cs.pendingBudgetResets {
578
- cs.pendingBudget = Pervasives.max(0., cs.pendingBudget -. held.items->Int.toFloat)
579
- }
580
-
581
- let hasBlockRegisters = (cs: t) => cs.fetchState.blockRegisterThrough !== None
582
- let isBlockRegisterIdle = (cs: t) => cs.blockRegisterRuns === 0
583
-
584
- // Queues a unit of register work behind the chain's latest one. Returns the
585
- // promise to wait on before running it, and the callback that settles it,
586
- // which must be called however the unit ends.
587
- let queueBlockRegisterRun = (cs: t) => {
588
- let previous = cs.blockRegisterTail
589
- let settle = ref(() => ())
590
- cs.blockRegisterTail = Promise.make((resolve, _) => settle := resolve)
591
- cs.blockRegisterRuns = cs.blockRegisterRuns + 1
592
- let finish = () => {
593
- cs.blockRegisterRuns = cs.blockRegisterRuns - 1
594
- settle.contents()
595
- }
596
- (previous, finish)
597
- }
598
-
599
- let canAdvanceBlockRegisters = (cs: t, ~through) =>
600
- cs.fetchState->FetchState.canAdvanceBlockRegisters(~through)
601
- let nextBlockRegisterItems = (cs: t, ~through, ~limit) =>
602
- cs.fetchState->FetchState.nextBlockRegisterItems(~through, ~limit)
603
- let blockRegisterItemsAfter = (cs: t, ~after, ~through, ~limit) =>
604
- cs.fetchState->FetchState.blockRegisterItemsAfter(~after, ~through, ~limit)
605
- let blockRegisterThrough = (cs: t) => cs.fetchState.blockRegisterThrough
606
- let blockRegisterFrontier = (cs: t) => cs.fetchState->FetchState.blockRegisterFrontier
607
-
608
- // Applies what a run of block passes alone registered, then lets block items
609
- // through its last block be generated.
610
- let applyBlockRegisters = (cs: t, ~registrations, ~through) => {
611
- let fs = switch registrations {
612
- | [] => cs.fetchState
613
- | _ =>
614
- cs.fetchState->FetchState.registerDynamicContracts(
615
- ~addressStore=cs.addressStore,
616
- ~onNotice=notice => cs.logger->logFetchStateNotice(notice),
617
- registrations,
618
- )
619
- }
620
- cs.fetchState = fs->FetchState.setBlockRegisterThrough(~through)
621
- }
622
-
623
- let markBlockRegistered = (cs: t, ~through) =>
624
- cs.fetchState = cs.fetchState->FetchState.setBlockRegisterThrough(~through)
625
-
626
556
  let isReady = (cs: t) => cs.timestampCaughtUpToHeadOrEndblock !== None
627
557
 
628
558
  // Block span over which a batch fully replaces the chain density estimate;
@@ -852,10 +782,10 @@ let takeFinished = (cs: t) =>
852
782
  }
853
783
  }
854
784
 
855
- let getHighestBlockBelowThreshold = (cs: t): int => {
856
- let highestBlockBelowThreshold = cs.fetchState.knownHeight - cs.maxReorgDepth
857
- highestBlockBelowThreshold < 0 ? 0 : highestBlockBelowThreshold
858
- }
785
+ // The block reorg detection compares from is itself in the window, so the
786
+ // highest block below it is the one before, where catch-up stops.
787
+ let getHighestBlockBelowThreshold = (cs: t): int =>
788
+ Pervasives.max(cs.fetchState.knownHeight - cs.maxReorgDepth - 1, 0)
859
789
 
860
790
  // True once the fetch frontier has reached the head/endBlock for this chain.
861
791
  let isFetchingAtHead = (cs: t) => cs.fetchState->FetchState.isFetchingAtHead
@@ -1053,6 +983,34 @@ let materializePageItems = async (
1053
983
  ))
1054
984
  }
1055
985
 
986
+ // Near the head: each new block in as few queries as possible, of a shape that
987
+ // stays the same while contracts keep being registered. Once every partition is
988
+ // close enough, the chain's dynamic contracts leave the server-side address
989
+ // filter for the rest of the run.
990
+ //
991
+ // Judged only when the chain learns a newer head. An RPC response repeats the
992
+ // height its query went out with, which can be hours old by the end of a
993
+ // backfill: judged against it, every block produced since would be fetched
994
+ // address-free.
995
+ let switchDynamicContractsToClientSideFilteringNearHead = (cs: t) =>
996
+ if (
997
+ !cs.fetchState.clientFilterPolicy.allDynamicContracts &&
998
+ cs.fetchState->FetchState.isWithinHeadClientFilteringDistance
999
+ ) {
1000
+ cs.fetchState =
1001
+ cs.fetchState->FetchState.switchDynamicContractsToClientSideFiltering(
1002
+ ~addressStore=cs.addressStore,
1003
+ )
1004
+ if cs.onEventRegistrations->Array.some(registration => registration.contractRegister !== None) {
1005
+ cs.logger->Logger.trace(
1006
+ "Near the head: dynamic contracts are fetched without their addresses for the rest of the run, and filtered on our side.",
1007
+ ~params={
1008
+ "contractNames": cs.fetchState.optimizedPartitions.dynamicContracts->Utils.Set.toArray,
1009
+ },
1010
+ )
1011
+ }
1012
+ }
1013
+
1056
1014
  let handleQueryResult = (
1057
1015
  cs: t,
1058
1016
  ~query: FetchState.query,
@@ -1076,6 +1034,7 @@ let handleQueryResult = (
1076
1034
  )
1077
1035
  }
1078
1036
 
1037
+ let previousKnownHeight = cs.fetchState.knownHeight
1079
1038
  cs.fetchState =
1080
1039
  fs
1081
1040
  ->FetchState.handleQueryResult(~query, ~latestFetchedBlock, ~newItems)
@@ -1083,6 +1042,9 @@ let handleQueryResult = (
1083
1042
 
1084
1043
  // The query is no longer in flight, so release its reservation.
1085
1044
  cs.pendingBudget = Pervasives.max(0., cs.pendingBudget -. query.itemsEst->Int.toFloat)
1045
+ if cs.fetchState.knownHeight > previousKnownHeight {
1046
+ cs->switchDynamicContractsToClientSideFilteringNearHead
1047
+ }
1086
1048
  }
1087
1049
 
1088
1050
  // Run reorg detection against a fetch response by merging its block-store page
@@ -1117,8 +1079,11 @@ let prepareReorg = (cs: t, ~eventsProcessedDiff) => {
1117
1079
  cs->resetPendingQueries
1118
1080
  }
1119
1081
 
1120
- let updateKnownHeight = (cs: t, ~knownHeight) =>
1082
+ // A chain waiting at its head goes address-free before querying the new block.
1083
+ let updateKnownHeight = (cs: t, ~knownHeight) => {
1121
1084
  cs.fetchState = cs.fetchState->FetchState.updateKnownHeight(~knownHeight)
1085
+ cs->switchDynamicContractsToClientSideFilteringNearHead
1086
+ }
1122
1087
 
1123
1088
  // In auto-exit mode, pin the endBlock to the earliest observed event block.
1124
1089
  let setEndBlockToFirstEvent = (cs: t, ~blockNumber) =>
@@ -83,7 +83,6 @@ function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, so
83
83
  processingBlockNumber: committedProgressBlockNumber,
84
84
  numEventsProcessed: numEventsProcessed,
85
85
  pendingBudget: 0,
86
- pendingBudgetResets: 0,
87
86
  chainDensity: chainDensity,
88
87
  entities: EntityTables.make(perChainEntities),
89
88
  safeCheckpointTracking: safeCheckpointTracking,
@@ -104,9 +103,7 @@ function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, so
104
103
  reorgDetectedBlock: undefined,
105
104
  rollbackTargetBlock: undefined,
106
105
  progressLatencyMs: undefined,
107
- committedProgressBlockTime: committedProgressBlockTime,
108
- blockRegisterTail: Promise.resolve(),
109
- blockRegisterRuns: 0
106
+ committedProgressBlockTime: committedProgressBlockTime
110
107
  };
111
108
  }
112
109
 
@@ -162,11 +159,16 @@ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInR
162
159
  onBlockRegistrations: []
163
160
  });
164
161
  let onEventRegistrations = match.onEventRegistrations;
165
- let onBlockRegistrations = match.onBlockRegistrations.map(reg => {
166
- let newrecord = {...reg};
167
- newrecord.startBlock = Stdlib_Option.getOr(reg.startBlock, startBlock);
168
- return newrecord;
169
- });
162
+ let onBlockRegistrations = match.onBlockRegistrations.map(reg => ({
163
+ index: reg.index,
164
+ name: reg.name,
165
+ chainId: reg.chainId,
166
+ startBlock: Stdlib_Option.getOr(reg.startBlock, startBlock),
167
+ endBlock: reg.endBlock,
168
+ interval: reg.interval,
169
+ handler: reg.handler,
170
+ blockFieldMask: reg.blockFieldMask
171
+ }));
170
172
  chainConfig.contracts.forEach(contract => {
171
173
  let contractStartBlock = contract.startBlock;
172
174
  if (contractStartBlock !== undefined && contractStartBlock < startBlock) {
@@ -186,7 +188,7 @@ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInR
186
188
  tmp = undefined;
187
189
  break;
188
190
  }
189
- let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, addressStore, addressRows, config.maxAddrInPartition, chainConfig.id, notice => logFetchStateNotice(logger$1, notice), (config.batchSize << 1), knownHeight, progressBlockNumber, onBlockRegistrations, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock), Primitive_option.some(tmp), isResumed, Stdlib_Option.isSome(config.subgraph));
191
+ let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, addressStore, addressRows, config.maxAddrInPartition, chainConfig.id, notice => logFetchStateNotice(logger$1, notice), (config.batchSize << 1), knownHeight, progressBlockNumber, onBlockRegistrations, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold || maxReorgDepth === 0 ? 0 : maxReorgDepth + 1 | 0, chainConfig.blockLag), chainConfig.blockThrottle, Primitive_option.some(firstEventBlock), Primitive_option.some(tmp), isResumed);
190
192
  let chainReorgCheckpoints = Stdlib_Array.filterMap(reorgCheckpoints, reorgCheckpoint => {
191
193
  if (reorgCheckpoint.chain_id === chainConfig.id) {
192
194
  return reorgCheckpoint;
@@ -194,7 +196,7 @@ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInR
194
196
  });
195
197
  let blockStore = BlockStore.make(config.ecosystem.name);
196
198
  let transactionStore = TransactionStore.make(config.ecosystem.name);
197
- let sources = ChainSources.make(chainConfig, onEventRegistrations, onBlockRegistrations, addressStore, lowercaseAddresses, blockStore, transactionStore, logger$1);
199
+ let sources = ChainSources.make(chainConfig, onEventRegistrations, onBlockRegistrations, addressStore, lowercaseAddresses, blockStore, transactionStore, logger$1, config.maxAddrInPartition);
198
200
  if (Utils.$$Array.notEmpty(chainReorgCheckpoints)) {
199
201
  let seedPage = BlockStore.fromJs(chainReorgCheckpoints.map(cp => ({
200
202
  blockNumber: cp.block_number,
@@ -223,10 +225,6 @@ function shouldChecksum(cs) {
223
225
  return cs.shouldChecksum;
224
226
  }
225
227
 
226
- function fetchState(cs) {
227
- return cs.fetchState;
228
- }
229
-
230
228
  function entities(cs) {
231
229
  return cs.entities;
232
230
  }
@@ -340,78 +338,6 @@ function startFetchingQueries(cs, queries) {
340
338
  function resetPendingQueries(cs) {
341
339
  cs.fetchState = FetchState.resetPendingQueries(cs.fetchState);
342
340
  cs.pendingBudget = 0;
343
- cs.pendingBudgetResets = cs.pendingBudgetResets + 1 | 0;
344
- }
345
-
346
- function holdExtraBudget(cs, items) {
347
- cs.pendingBudget = cs.pendingBudget + items;
348
- return {
349
- items: items,
350
- resets: cs.pendingBudgetResets
351
- };
352
- }
353
-
354
- function releaseExtraBudget(cs, held) {
355
- if (held.resets === cs.pendingBudgetResets) {
356
- cs.pendingBudget = Primitive_float.max(0, cs.pendingBudget - held.items);
357
- return;
358
- }
359
- }
360
-
361
- function hasBlockRegisters(cs) {
362
- return cs.fetchState.blockRegisterThrough !== undefined;
363
- }
364
-
365
- function isBlockRegisterIdle(cs) {
366
- return cs.blockRegisterRuns === 0;
367
- }
368
-
369
- function queueBlockRegisterRun(cs) {
370
- let previous = cs.blockRegisterTail;
371
- let settle = {
372
- contents: () => {}
373
- };
374
- cs.blockRegisterTail = new Promise((resolve, param) => {
375
- settle.contents = resolve;
376
- });
377
- cs.blockRegisterRuns = cs.blockRegisterRuns + 1 | 0;
378
- let finish = () => {
379
- cs.blockRegisterRuns = cs.blockRegisterRuns - 1 | 0;
380
- settle.contents();
381
- };
382
- return [
383
- previous,
384
- finish
385
- ];
386
- }
387
-
388
- function canAdvanceBlockRegisters(cs, through) {
389
- return FetchState.canAdvanceBlockRegisters(cs.fetchState, through);
390
- }
391
-
392
- function nextBlockRegisterItems(cs, through, limit) {
393
- return FetchState.nextBlockRegisterItems(cs.fetchState, through, limit);
394
- }
395
-
396
- function blockRegisterItemsAfter(cs, after, through, limit) {
397
- return FetchState.blockRegisterItemsAfter(cs.fetchState, after, through, limit);
398
- }
399
-
400
- function blockRegisterThrough(cs) {
401
- return cs.fetchState.blockRegisterThrough;
402
- }
403
-
404
- function blockRegisterFrontier(cs) {
405
- return FetchState.blockRegisterFrontier(cs.fetchState);
406
- }
407
-
408
- function applyBlockRegisters(cs, registrations, through) {
409
- let fs = registrations.length !== 0 ? FetchState.registerDynamicContracts(cs.fetchState, cs.addressStore, notice => logFetchStateNotice(cs.logger, notice), undefined, registrations) : cs.fetchState;
410
- cs.fetchState = FetchState.setBlockRegisterThrough(fs, through);
411
- }
412
-
413
- function markBlockRegistered(cs, through) {
414
- cs.fetchState = FetchState.setBlockRegisterThrough(cs.fetchState, through);
415
341
  }
416
342
 
417
343
  function isReady(cs) {
@@ -568,12 +494,7 @@ function takeFinished(cs) {
568
494
  }
569
495
 
570
496
  function getHighestBlockBelowThreshold(cs) {
571
- let highestBlockBelowThreshold = cs.fetchState.knownHeight - cs.maxReorgDepth | 0;
572
- if (highestBlockBelowThreshold < 0) {
573
- return 0;
574
- } else {
575
- return highestBlockBelowThreshold;
576
- }
497
+ return Primitive_int.max((cs.fetchState.knownHeight - cs.maxReorgDepth | 0) - 1 | 0, 0);
577
498
  }
578
499
 
579
500
  function isFetchingAtHead(cs) {
@@ -721,10 +642,27 @@ async function materializePageItems(items, transactionStore, blockStore, shouldC
721
642
  ]);
722
643
  }
723
644
 
645
+ function switchDynamicContractsToClientSideFilteringNearHead(cs) {
646
+ if (!cs.fetchState.clientFilterPolicy.allDynamicContracts && FetchState.isWithinHeadClientFilteringDistance(cs.fetchState)) {
647
+ cs.fetchState = FetchState.switchDynamicContractsToClientSideFiltering(cs.fetchState, cs.addressStore);
648
+ if (cs.onEventRegistrations.some(registration => registration.contractRegister !== undefined)) {
649
+ return Logger.trace(cs.logger, "Near the head: dynamic contracts are fetched without their addresses for the rest of the run, and filtered on our side.", {
650
+ contractNames: Array.from(cs.fetchState.optimizedPartitions.dynamicContracts)
651
+ });
652
+ } else {
653
+ return;
654
+ }
655
+ }
656
+ }
657
+
724
658
  function handleQueryResult(cs, query, newItems, newRegistrations, latestFetchedBlock, knownHeight) {
725
659
  let fs = newRegistrations.length !== 0 ? FetchState.registerDynamicContracts(cs.fetchState, cs.addressStore, notice => logFetchStateNotice(cs.logger, notice), Primitive_int.max(knownHeight, latestFetchedBlock), newRegistrations) : cs.fetchState;
660
+ let previousKnownHeight = cs.fetchState.knownHeight;
726
661
  cs.fetchState = FetchState.updateKnownHeight(FetchState.handleQueryResult(fs, query, latestFetchedBlock, newItems), knownHeight);
727
662
  cs.pendingBudget = Primitive_float.max(0, cs.pendingBudget - query.itemsEst);
663
+ if (cs.fetchState.knownHeight > previousKnownHeight) {
664
+ return switchDynamicContractsToClientSideFilteringNearHead(cs);
665
+ }
728
666
  }
729
667
 
730
668
  function registerReorgGuard(cs, blockStore, knownHeight) {
@@ -757,6 +695,7 @@ function prepareReorg(cs, eventsProcessedDiff) {
757
695
 
758
696
  function updateKnownHeight(cs, knownHeight) {
759
697
  cs.fetchState = FetchState.updateKnownHeight(cs.fetchState, knownHeight);
698
+ switchDynamicContractsToClientSideFilteringNearHead(cs);
760
699
  }
761
700
 
762
701
  function setEndBlockToFirstEvent(cs, blockNumber) {
@@ -765,14 +704,42 @@ function setEndBlockToFirstEvent(cs, blockNumber) {
765
704
  if (blockNumber >= currentEndBlock) {
766
705
  return;
767
706
  }
768
- let newrecord = {...cs.fetchState};
769
- newrecord.endBlock = blockNumber;
770
- cs.fetchState = newrecord;
707
+ let init = cs.fetchState;
708
+ cs.fetchState = {
709
+ optimizedPartitions: init.optimizedPartitions,
710
+ startBlock: init.startBlock,
711
+ endBlock: blockNumber,
712
+ normalSelection: init.normalSelection,
713
+ chainId: init.chainId,
714
+ latestOnBlockBlockNumber: init.latestOnBlockBlockNumber,
715
+ blockLag: init.blockLag,
716
+ blockThrottle: init.blockThrottle,
717
+ buffer: init.buffer,
718
+ maxOnBlockBufferSize: init.maxOnBlockBufferSize,
719
+ onBlockRegistrations: init.onBlockRegistrations,
720
+ knownHeight: init.knownHeight,
721
+ firstEventBlock: init.firstEventBlock,
722
+ clientFilterPolicy: init.clientFilterPolicy
723
+ };
771
724
  return;
772
725
  }
773
- let newrecord$1 = {...cs.fetchState};
774
- newrecord$1.endBlock = blockNumber;
775
- cs.fetchState = newrecord$1;
726
+ let init$1 = cs.fetchState;
727
+ cs.fetchState = {
728
+ optimizedPartitions: init$1.optimizedPartitions,
729
+ startBlock: init$1.startBlock,
730
+ endBlock: blockNumber,
731
+ normalSelection: init$1.normalSelection,
732
+ chainId: init$1.chainId,
733
+ latestOnBlockBlockNumber: init$1.latestOnBlockBlockNumber,
734
+ blockLag: init$1.blockLag,
735
+ blockThrottle: init$1.blockThrottle,
736
+ buffer: init$1.buffer,
737
+ maxOnBlockBufferSize: init$1.maxOnBlockBufferSize,
738
+ onBlockRegistrations: init$1.onBlockRegistrations,
739
+ knownHeight: init$1.knownHeight,
740
+ firstEventBlock: init$1.firstEventBlock,
741
+ clientFilterPolicy: init$1.clientFilterPolicy
742
+ };
776
743
  }
777
744
 
778
745
  function enterReorgThreshold(cs) {
@@ -920,9 +887,23 @@ function applyBatchProgress(cs, batch, blockTimestampName) {
920
887
  if (match === undefined) {
921
888
  let firstEventBlock = Batch.findFirstEventBlockNumber(batch, chainId);
922
889
  if (firstEventBlock !== undefined) {
923
- let newrecord = {...cs.fetchState};
924
- newrecord.firstEventBlock = firstEventBlock;
925
- cs.fetchState = newrecord;
890
+ let init = cs.fetchState;
891
+ cs.fetchState = {
892
+ optimizedPartitions: init.optimizedPartitions,
893
+ startBlock: init.startBlock,
894
+ endBlock: init.endBlock,
895
+ normalSelection: init.normalSelection,
896
+ chainId: init.chainId,
897
+ latestOnBlockBlockNumber: init.latestOnBlockBlockNumber,
898
+ blockLag: init.blockLag,
899
+ blockThrottle: init.blockThrottle,
900
+ buffer: init.buffer,
901
+ maxOnBlockBufferSize: init.maxOnBlockBufferSize,
902
+ onBlockRegistrations: init.onBlockRegistrations,
903
+ knownHeight: init.knownHeight,
904
+ firstEventBlock: firstEventBlock,
905
+ clientFilterPolicy: init.clientFilterPolicy
906
+ };
926
907
  }
927
908
  }
928
909
  let deltaBlocks = chainAfterBatch.progressBlockNumber - cs.committedProgressBlockNumber | 0;
@@ -1025,7 +1006,6 @@ export {
1025
1006
  blockStore,
1026
1007
  transactionStore,
1027
1008
  shouldChecksum,
1028
- fetchState,
1029
1009
  entities,
1030
1010
  resetEntities,
1031
1011
  sourceManager,
@@ -1038,18 +1018,6 @@ export {
1038
1018
  committedProgressBlockTime,
1039
1019
  numEventsProcessed,
1040
1020
  pendingBudget,
1041
- holdExtraBudget,
1042
- releaseExtraBudget,
1043
- hasBlockRegisters,
1044
- isBlockRegisterIdle,
1045
- queueBlockRegisterRun,
1046
- canAdvanceBlockRegisters,
1047
- nextBlockRegisterItems,
1048
- blockRegisterItemsAfter,
1049
- blockRegisterThrough,
1050
- blockRegisterFrontier,
1051
- applyBlockRegisters,
1052
- markBlockRegistered,
1053
1021
  startFetchingQueries,
1054
1022
  timestampCaughtUpToHeadOrEndblock,
1055
1023
  recordBlockRangeFetch,
@@ -58,8 +58,6 @@ let logger: t => Logger.t
58
58
  let blockStore: t => BlockStore.t
59
59
  let transactionStore: t => TransactionStore.t
60
60
  let shouldChecksum: t => bool
61
- // The chain's fetch state, read-only: for the round a registration belongs to.
62
- let fetchState: t => FetchState.t
63
61
  let entities: t => EntityTables.t
64
62
  let resetEntities: (t, ~perChainEntities: array<Internal.entityConfig>) => unit
65
63
  let sourceManager: t => SourceManager.t
@@ -77,30 +75,6 @@ let committedProgressBlockNumber: t => int
77
75
  let committedProgressBlockTime: t => option<int>
78
76
  let numEventsProcessed: t => float
79
77
  let pendingBudget: t => float
80
- type heldBudget
81
- let holdExtraBudget: (t, ~items: int) => heldBudget
82
- let releaseExtraBudget: (t, heldBudget) => unit
83
- // Subgraph mode: the register passes of block handlers that create data
84
- // sources. See `FetchState.blockRegisterThrough`.
85
- let hasBlockRegisters: t => bool
86
- let isBlockRegisterIdle: t => bool
87
- let queueBlockRegisterRun: t => (promise<unit>, unit => unit)
88
- let canAdvanceBlockRegisters: (t, ~through: int) => bool
89
- let nextBlockRegisterItems: (t, ~through: int, ~limit: int) => option<(array<Internal.item>, int)>
90
- let blockRegisterItemsAfter: (
91
- t,
92
- ~after: int,
93
- ~through: int,
94
- ~limit: int,
95
- ) => option<(array<Internal.item>, int)>
96
- let blockRegisterThrough: t => option<int>
97
- let blockRegisterFrontier: t => int
98
- let applyBlockRegisters: (
99
- t,
100
- ~registrations: array<AddressStore.registration>,
101
- ~through: int,
102
- ) => unit
103
- let markBlockRegistered: (t, ~through: int) => unit
104
78
  let startFetchingQueries: (t, ~queries: array<FetchState.query>) => unit
105
79
  let timestampCaughtUpToHeadOrEndblock: t => option<Date.t>
106
80
 
package/src/Clock.res ADDED
@@ -0,0 +1,57 @@
1
+ // What the source layer reads time from and arms its timers on. A test can hand
2
+ // it a clock that only moves when the test moves it, which takes the scheduler
3
+ // out of every race between a timer and the step a test is taking. The label
4
+ // names a timer in that clock's timeline; the real clock ignores it.
5
+ type timer
6
+
7
+ type t = {
8
+ now: unit => float,
9
+ setTimeout: (~label: string, unit => unit, int) => timer,
10
+ clearTimeout: timer => unit,
11
+ random: unit => float,
12
+ }
13
+
14
+ // Test-only. Set while a test drives a run on virtual time, so code that reaches
15
+ // past the clock it was given fails where it does, instead of arming a timer
16
+ // the test can neither see nor move.
17
+ let refuseReal = ref(false)
18
+
19
+ let refused = what =>
20
+ JsError.throwWithMessage(
21
+ `Clock.real ${what} on virtual time. Use the clock the code was given, so advanceTime can see and move it.`,
22
+ )
23
+
24
+ // Monotonic: every reading is only ever compared with another, and a wall
25
+ // clock corrected mid-run would make a connection look like it served for
26
+ // minutes, or a benched source look recovered.
27
+ let real: t = {
28
+ now: () => refuseReal.contents ? refused("read the time") : Performance.now(),
29
+ // A zero delay is a turn of the event loop on either clock.
30
+ setTimeout: (~label, callback, millis) =>
31
+ refuseReal.contents && millis > 0
32
+ ? refused(`armed "${label}"`)
33
+ : setTimeout(callback, millis)->(Utils.magic: timeoutId => timer),
34
+ clearTimeout: timer => clearTimeout(timer->(Utils.magic: timer => timeoutId)),
35
+ random: Math.random,
36
+ }
37
+
38
+ let delay = (clock: t, ~label, millis) =>
39
+ Promise.make((resolve, _reject) => clock.setTimeout(~label, () => resolve(), millis)->ignore)
40
+
41
+ // Half the delay fixed, half spread across it. Every indexer pointed at one
42
+ // provider loses its stream, or gives up on a quiet chain, in the same instant
43
+ // that provider blinks, and putting them all back on the same schedule is how a
44
+ // blip becomes a stampede.
45
+ let jitter = (clock: t, delay) =>
46
+ delay / 2 + (clock.random() *. (delay / 2)->Int.toFloat)->Float.toInt
47
+
48
+ // Clearing a pending timer and forgetting it are one action. A ref left holding
49
+ // a spent timer reads as one still pending, and the next clear looks like it
50
+ // did something.
51
+ let clearRef = (clock: t, timer: ref<option<timer>>) => {
52
+ switch timer.contents {
53
+ | Some(timer) => clock.clearTimeout(timer)
54
+ | None => ()
55
+ }
56
+ timer := None
57
+ }