envio 3.15.0 → 3.16.0-subgraph

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 +11 -2
  3. package/fuel.schema.json +10 -1
  4. package/index.d.ts +6 -0
  5. package/licenses/README.md +1 -1
  6. package/package.json +10 -9
  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 +7 -0
  11. package/src/Bin.res.mjs +8 -0
  12. package/src/ChainFetching.res +450 -16
  13. package/src/ChainFetching.res.mjs +403 -32
  14. package/src/ChainState.res +124 -7
  15. package/src/ChainState.res.mjs +128 -67
  16. package/src/ChainState.resi +26 -0
  17. package/src/Clock.res +57 -0
  18. package/src/Clock.res.mjs +72 -0
  19. package/src/Config.res +31 -3
  20. package/src/Config.res.mjs +15 -4
  21. package/src/ContractRegisterContext.res +3 -6
  22. package/src/ContractRegisterContext.res.mjs +4 -2
  23. package/src/Core.res +95 -36
  24. package/src/Core.res.mjs +90 -1
  25. package/src/CrossChainState.res +12 -2
  26. package/src/CrossChainState.res.mjs +3 -3
  27. package/src/Ecosystem.res +7 -4
  28. package/src/Ecosystem.res.mjs +8 -8
  29. package/src/EffectCacheLookup.res +98 -0
  30. package/src/EffectCacheLookup.res.mjs +116 -0
  31. package/src/EffectState.res +10 -2
  32. package/src/EffectState.res.mjs +8 -4
  33. package/src/EffectState.resi +3 -1
  34. package/src/EntityId.res +2 -7
  35. package/src/EntityId.res.mjs +1 -8
  36. package/src/EntityTables.res +4 -1
  37. package/src/EntityTables.res.mjs +1 -1
  38. package/src/Env.res +20 -0
  39. package/src/Env.res.mjs +16 -0
  40. package/src/EventProcessing.res +38 -1
  41. package/src/EventProcessing.res.mjs +28 -1
  42. package/src/FetchState.res +408 -73
  43. package/src/FetchState.res.mjs +361 -91
  44. package/src/FinalizeBackfill.res +2 -4
  45. package/src/FinalizeBackfill.res.mjs +3 -4
  46. package/src/HandlerLoader.res +39 -15
  47. package/src/HandlerLoader.res.mjs +27 -8
  48. package/src/HandlerRegister.res +4 -0
  49. package/src/HandlerRegister.res.mjs +5 -2
  50. package/src/HandlerRegister.resi +2 -0
  51. package/src/InMemoryTable.res +17 -16
  52. package/src/InMemoryTable.res.mjs +14 -15
  53. package/src/IndexerState.res +28 -4
  54. package/src/IndexerState.res.mjs +19 -6
  55. package/src/IndexerState.resi +4 -0
  56. package/src/Internal.res +61 -49
  57. package/src/Internal.res.mjs +36 -80
  58. package/src/LoadLayer.res +54 -15
  59. package/src/LoadLayer.res.mjs +75 -45
  60. package/src/LoadLayer.resi +26 -0
  61. package/src/Main.res +14 -1
  62. package/src/Main.res.mjs +4 -3
  63. package/src/Persistence.res +3 -23
  64. package/src/Persistence.res.mjs +3 -3
  65. package/src/PreloadLookahead.res +202 -0
  66. package/src/PreloadLookahead.res.mjs +218 -0
  67. package/src/Rollback.res +0 -1
  68. package/src/Rollback.res.mjs +1 -1
  69. package/src/RunScope.res +3 -0
  70. package/src/SafeCheckpointTracking.res +4 -4
  71. package/src/SafeCheckpointTracking.res.mjs +1 -1
  72. package/src/SimulateItems.res +42 -26
  73. package/src/SimulateItems.res.mjs +40 -16
  74. package/src/StagedRows.res +106 -0
  75. package/src/StagedRows.res.mjs +102 -0
  76. package/src/Staging.res +32 -14
  77. package/src/Staging.res.mjs +17 -20
  78. package/src/Storage.res +303 -948
  79. package/src/Storage.res.mjs +229 -708
  80. package/src/SubgraphLog.res +19 -0
  81. package/src/SubgraphLog.res.mjs +26 -0
  82. package/src/Supervisor.res +75 -56
  83. package/src/Supervisor.res.mjs +55 -26
  84. package/src/SyncWrites.res +107 -0
  85. package/src/SyncWrites.res.mjs +98 -0
  86. package/src/TestIndexer.res +22 -27
  87. package/src/TestIndexer.res.mjs +20 -17
  88. package/src/Throttler.res +15 -8
  89. package/src/Throttler.res.mjs +9 -6
  90. package/src/Throttler.resi +1 -1
  91. package/src/UserContext.res +419 -46
  92. package/src/UserContext.res.mjs +318 -30
  93. package/src/Utils.res +17 -6
  94. package/src/Utils.res.mjs +12 -6
  95. package/src/Writing.res +0 -1
  96. package/src/Writing.res.mjs +1 -1
  97. package/src/bindings/ClickHouse.res +0 -322
  98. package/src/bindings/ClickHouse.res.mjs +0 -338
  99. package/src/bindings/StorageClient.res +108 -174
  100. package/src/bindings/StorageClient.res.mjs +19 -8
  101. package/src/bindings/Vitest.res +0 -26
  102. package/src/bindings/Vitest.res.mjs +0 -3
  103. package/src/db/Table.res +24 -150
  104. package/src/db/Table.res.mjs +38 -272
  105. package/src/sources/AddressSet.res +2 -0
  106. package/src/sources/AddressStore.res +3 -0
  107. package/src/sources/CallSource.res +274 -0
  108. package/src/sources/CallSource.res.mjs +196 -0
  109. package/src/sources/ChainSources.res +2 -0
  110. package/src/sources/ChainSources.res.mjs +2 -2
  111. package/src/sources/EvmChain.res +10 -1
  112. package/src/sources/EvmChain.res.mjs +6 -3
  113. package/src/sources/EvmHyperSyncSource.res +2 -2
  114. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  115. package/src/sources/EvmRpcClient.res +13 -3
  116. package/src/sources/EvmRpcClient.res.mjs +4 -3
  117. package/src/sources/EvmRpcWs.res +4 -3
  118. package/src/sources/EvmRpcWs.res.mjs +2 -2
  119. package/src/sources/HeightFeed.res +31 -10
  120. package/src/sources/HeightFeed.res.mjs +10 -6
  121. package/src/sources/HeightStream.res +32 -17
  122. package/src/sources/HeightStream.res.mjs +10 -10
  123. package/src/sources/HyperSync.res +2 -1
  124. package/src/sources/HyperSync.res.mjs +2 -1
  125. package/src/sources/HyperSyncSSE.res +4 -6
  126. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  127. package/src/sources/RpcSource.res +10 -1
  128. package/src/sources/RpcSource.res.mjs +4 -3
  129. package/src/sources/Source.res +3 -0
  130. package/src/sources/SourceManager.res +84 -77
  131. package/src/sources/SourceManager.res.mjs +17 -20
  132. package/src/sources/SourceManager.resi +3 -4
  133. package/src/sources/StartBlockResolver.res +1 -0
  134. package/src/sources/StartBlockResolver.res.mjs +3 -2
  135. package/src/sources/SvmHyperSyncSource.res +2 -2
  136. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  137. package/src/subgraph/abi-types.ts +84 -0
  138. package/src/subgraph/aggregations.ts +745 -0
  139. package/src/subgraph/as-package.ts +143 -0
  140. package/src/subgraph/assemblyscript-regex.ts +67 -0
  141. package/src/subgraph/assemblyscript.ts +731 -0
  142. package/src/subgraph/blocks.ts +398 -0
  143. package/src/subgraph/calls-source.ts +702 -0
  144. package/src/subgraph/calls.ts +258 -0
  145. package/src/subgraph/conformance.ts +106 -0
  146. package/src/subgraph/errors.ts +85 -0
  147. package/src/subgraph/graft.ts +73 -0
  148. package/src/subgraph/graph-cli-worker.mjs +35 -0
  149. package/src/subgraph/graph-cli.ts +900 -0
  150. package/src/subgraph/graph-node-decimal.ts +199 -0
  151. package/src/subgraph/graph-ts-enums.ts +28 -0
  152. package/src/subgraph/graph-ts-types/VERSION +2 -0
  153. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
  154. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
  155. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
  156. package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
  157. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
  158. package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
  159. package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
  160. package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
  161. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  162. package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
  163. package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
  164. package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
  165. package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
  166. package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
  167. package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
  168. package/src/subgraph/graph-ts-types/index.d.ts +102 -0
  169. package/src/subgraph/graph-ts.ts +4339 -0
  170. package/src/subgraph/hosts.ts +554 -0
  171. package/src/subgraph/log.ts +28 -0
  172. package/src/subgraph/receipts.ts +184 -0
  173. package/src/subgraph/register-slots.ts +93 -0
  174. package/src/subgraph/rollup.ts +109 -0
  175. package/src/subgraph/rpc.ts +337 -0
  176. package/src/subgraph/runtime.ts +2059 -0
  177. package/src/subgraph/scope.ts +176 -0
  178. package/src/subgraph/stats.ts +42 -0
  179. package/src/subgraph/template-instances.ts +66 -0
  180. package/src/subgraph/toolchain.ts +327 -0
  181. package/src/subgraph/transient.ts +176 -0
  182. package/svm.schema.json +11 -2
  183. package/src/PgWriting.res +0 -36
  184. package/src/PgWriting.res.mjs +0 -34
  185. package/src/db/IndexDefinition.res +0 -47
  186. package/src/db/IndexDefinition.res.mjs +0 -67
@@ -0,0 +1,19 @@
1
+ // Every line the subgraph runtime logs, and every line a mapping logs through
2
+ // graph-ts (`uinfo`, `uwarn`, ...), as it is logged. A test indexer's own logger
3
+ // is silent, so this is how a test reads them. Compiled to JavaScript so a test
4
+ // can import it from an installed envio, where TypeScript isn't stripped.
5
+
6
+ type listener = (string, string) => unit
7
+
8
+ let listeners: array<listener> = []
9
+
10
+ let onLog = (listener: listener) => {
11
+ listeners->Array.push(listener)
12
+ () =>
13
+ switch listeners->Array.indexOf(listener) {
14
+ | -1 => ()
15
+ | index => listeners->Array.splice(~start=index, ~remove=1, ~insert=[])
16
+ }
17
+ }
18
+
19
+ let notify = (level, message) => listeners->Array.forEach(listener => listener(level, message))
@@ -0,0 +1,26 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+
4
+ let listeners = [];
5
+
6
+ function onLog(listener) {
7
+ listeners.push(listener);
8
+ return () => {
9
+ let index = listeners.indexOf(listener);
10
+ if (index !== -1) {
11
+ listeners.splice(index, 1);
12
+ return;
13
+ }
14
+ };
15
+ }
16
+
17
+ function notify(level, message) {
18
+ listeners.forEach(listener => listener(level, message));
19
+ }
20
+
21
+ export {
22
+ listeners,
23
+ onLog,
24
+ notify,
25
+ }
26
+ /* No side effect */
@@ -374,74 +374,93 @@ let releaseIfAtHead = group =>
374
374
  )
375
375
  }
376
376
 
377
- // The run's chains as an unsplit indexer reports them before it has fetched
378
- // anything: at their configured blocks, with nothing indexed. A display draws
379
- // these for a worker it hasn't heard from yet.
380
- let configuredChains = (config: Config.t): array<Metrics.chainMetrics> =>
377
+ // The run's chains as a worker reports them before it has fetched anything:
378
+ // where `ChainState.makeFromDbState` resumes them. A display draws these for a
379
+ // worker it hasn't heard from yet, and its first sight of a chain is what it
380
+ // measures the sync pace from, so a resumed chain drawn from its start block
381
+ // would pass the earlier runs' progress off as this one's.
382
+ let resumedChains = (config: Config.t, ~resumed: array<Persistence.initialChainState>): array<
383
+ Metrics.chainMetrics,
384
+ > =>
381
385
  config.chainMap
382
386
  ->ChainMap.values
383
387
  ->Array.map((chain): Metrics.chainMetrics => {
384
- chainId: chain.id,
385
- poweredByHyperSync: switch chain.sourceConfig {
386
- | EvmSourceConfig({hypersync}) => hypersync->Option.isSome
387
- | FuelSourceConfig(_) | SvmSourceConfig(_) => true
388
- | SimulateSourceConfig(_) | CustomSources(_) => false
389
- },
390
- firstEventBlockNumber: None,
391
- latestProcessedBlock: None,
392
- timestampCaughtUpToHeadOrEndblock: None,
393
- numEventsProcessed: 0.,
394
- latestFetchedBlockNumber: 0,
395
- knownHeight: 0,
396
- numBatchesFetched: 0,
397
- // A chain resolves `start_block: latest` against its own head as it starts,
398
- // which is a worker's to do and no supervisor's to guess.
399
- startBlock: switch chain.startBlock {
400
- | Block(block) => block
401
- | Latest => 0
402
- },
403
- endBlock: chain.endBlock,
404
- numAddresses: 0,
405
- addressesByContract: [],
406
- isReady: false,
407
- sourceBlockNumber: 0,
408
- progressBlockNumber: -1,
409
- progressLatencyMs: None,
410
- progressBlockTime: None,
411
- concurrency: 0,
412
- partitionsCount: 0,
413
- bufferSize: 0,
414
- bufferBlockNumber: -1,
415
- idleSeconds: 0.,
416
- waitingForNewBlockSeconds: 0.,
417
- queryingSeconds: 0.,
418
- blockRangeFetchSeconds: 0.,
419
- blockRangeParseSeconds: 0.,
420
- blockRangeFetchCount: 0.,
421
- blockRangeFetchedEvents: 0.,
422
- blockRangeFetchedBlocks: 0.,
423
- reorgCount: 0,
424
- reorgDetectedBlock: None,
425
- rollbackTargetBlock: None,
426
- rateLimitTimeMs: 0.,
427
- rateLimitResetInMs: None,
388
+ let row = resumed->Array.find(row => row.id == chain.id)
389
+ let startBlock = row->Option.mapOr(chain->Config.startBlockOrZero, row => row.startBlock)
390
+ let endBlock = row->Option.mapOr(chain.endBlock, row => row.endBlock)
391
+ let progressBlockNumber = switch row {
392
+ | Some({progressBlockNumber}) if progressBlockNumber >= 0 => progressBlockNumber
393
+ | _ => startBlock - 1
394
+ }
395
+ let sourceBlockNumber = row->Option.mapOr(0, row => row.sourceBlockNumber)
396
+ let timestampCaughtUpToHeadOrEndblock =
397
+ row->Option.flatMap(row => row.timestampCaughtUpToHeadOrEndblock)
398
+ let metrics: Metrics.chainMetrics = {
399
+ chainId: chain.id,
400
+ poweredByHyperSync: switch chain.sourceConfig {
401
+ | EvmSourceConfig({hypersync}) => hypersync->Option.isSome
402
+ | FuelSourceConfig(_) | SvmSourceConfig(_) => true
403
+ | SimulateSourceConfig(_) | CustomSources(_) => false
404
+ },
405
+ firstEventBlockNumber: row->Option.flatMap(row => row.firstEventBlockNumber),
406
+ latestProcessedBlock: progressBlockNumber === -1 ? None : Some(progressBlockNumber),
407
+ timestampCaughtUpToHeadOrEndblock,
408
+ numEventsProcessed: row->Option.mapOr(0., row => row.numEventsProcessed),
409
+ latestFetchedBlockNumber: Pervasives.max(progressBlockNumber, 0),
410
+ knownHeight: sourceBlockNumber,
411
+ numBatchesFetched: 0,
412
+ startBlock,
413
+ endBlock,
414
+ numAddresses: 0,
415
+ addressesByContract: [],
416
+ isReady: timestampCaughtUpToHeadOrEndblock->Option.isSome,
417
+ sourceBlockNumber,
418
+ progressBlockNumber,
419
+ progressLatencyMs: None,
420
+ progressBlockTime: row->Option.flatMap(row => row.progressBlockTime),
421
+ concurrency: 0,
422
+ partitionsCount: 0,
423
+ bufferSize: 0,
424
+ bufferBlockNumber: progressBlockNumber,
425
+ idleSeconds: 0.,
426
+ waitingForNewBlockSeconds: 0.,
427
+ queryingSeconds: 0.,
428
+ blockRangeFetchSeconds: 0.,
429
+ blockRangeParseSeconds: 0.,
430
+ blockRangeFetchCount: 0.,
431
+ blockRangeFetchedEvents: 0.,
432
+ blockRangeFetchedBlocks: 0.,
433
+ reorgCount: 0,
434
+ reorgDetectedBlock: None,
435
+ rollbackTargetBlock: None,
436
+ rateLimitTimeMs: 0.,
437
+ rateLimitResetInMs: None,
438
+ }
439
+ switch (metrics->Metrics.hasProcessedToEndblock, endBlock) {
440
+ | (true, Some(endBlock)) => {...metrics, knownHeight: endBlock}
441
+ | _ => metrics
442
+ }
428
443
  })
429
444
 
430
445
  // Per worker rather than all or nothing: a worker done within its first report
431
446
  // interval is heard from only as it exits, and a display holding just its
432
447
  // siblings' finished chains would read as synced while it still indexes.
433
- let displayedSnapshots = (running: array<running>, ~config, ~empty: Metrics.t) => {
434
- let configured = configuredChains(config)
448
+ let displayedSnapshots = (
449
+ running: array<running>,
450
+ ~resumedChains: array<Metrics.chainMetrics>,
451
+ ~empty: Metrics.t,
452
+ ) =>
435
453
  running->Array.map(r =>
436
454
  switch r.snapshot {
437
455
  | Some(snapshot) => snapshot
438
456
  | None => {
439
457
  ...empty,
440
- chains: configured->Array.filter(chain => r.worker.chainIds->Array.includes(chain.chainId)),
458
+ chains: resumedChains->Array.filter(chain =>
459
+ r.worker.chainIds->Array.includes(chain.chainId)
460
+ ),
441
461
  }
442
462
  }
443
463
  )
444
- }
445
464
 
446
465
  // Runs the group: creates the schema for every chain, forks a worker per plan
447
466
  // entry, and serves the run's metrics, console and display from what they
@@ -481,10 +500,9 @@ let run = async (~config: Config.t, ~logger, ~workers: array<worker>, ~reset) =>
481
500
  let shouldUseTui = Tui.shouldUse()
482
501
  // A run that resumed with every chain already caught up owes nobody a wait:
483
502
  // its workers start realtime and there is no barrier to open.
503
+ let resumed = (persistence->Persistence.getInitializedState).chains
484
504
  let holdRealtime =
485
- (persistence->Persistence.getInitializedState).chains->Array.some(chain =>
486
- chain.timestampCaughtUpToHeadOrEndblock->Option.isNone
487
- )
505
+ resumed->Array.some(chain => chain.timestampCaughtUpToHeadOrEndblock->Option.isNone)
488
506
  let group = {running: [], stopping: false, holdingRealtime: holdRealtime}
489
507
  group.running =
490
508
  workers->Array.mapWithIndex((worker, workerIndex) =>
@@ -534,8 +552,9 @@ let run = async (~config: Config.t, ~logger, ~workers: array<worker>, ~reset) =>
534
552
  )
535
553
 
536
554
  if shouldUseTui {
555
+ let resumedChains = resumedChains(config, ~resumed)
537
556
  Tui.start(~config, ~logger, ~getMetrics=() =>
538
- group.running->displayedSnapshots(~config, ~empty=[]->merge)->merge
557
+ group.running->displayedSnapshots(~resumedChains, ~empty=[]->merge)->merge
539
558
  )
540
559
  }
541
560
 
@@ -22,6 +22,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
22
22
  import * as Child_process from "child_process";
23
23
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
24
24
  import * as CrossChainState from "./CrossChainState.res.mjs";
25
+ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
25
26
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
26
27
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
27
28
 
@@ -313,8 +314,20 @@ function releaseIfAtHead(group) {
313
314
  }
314
315
  }
315
316
 
316
- function configuredChains(config) {
317
+ function resumedChains(config, resumed) {
317
318
  return ChainMap.values(config.chainMap).map(chain => {
319
+ let row = resumed.find(row => Primitive_object.equal(row.id, chain.id));
320
+ let startBlock = Stdlib_Option.mapOr(row, Config.startBlockOrZero(chain), row => row.startBlock);
321
+ let endBlock = Stdlib_Option.mapOr(row, chain.endBlock, row => row.endBlock);
322
+ let progressBlockNumber;
323
+ if (row !== undefined) {
324
+ let progressBlockNumber$1 = row.progressBlockNumber;
325
+ progressBlockNumber = progressBlockNumber$1 >= 0 ? progressBlockNumber$1 : startBlock - 1 | 0;
326
+ } else {
327
+ progressBlockNumber = startBlock - 1 | 0;
328
+ }
329
+ let sourceBlockNumber = Stdlib_Option.mapOr(row, 0, row => row.sourceBlockNumber);
330
+ let timestampCaughtUpToHeadOrEndblock = Stdlib_Option.flatMap(row, row => row.timestampCaughtUpToHeadOrEndblock);
318
331
  let match = chain.sourceConfig;
319
332
  let tmp;
320
333
  switch (match.TAG) {
@@ -330,32 +343,37 @@ function configuredChains(config) {
330
343
  tmp = false;
331
344
  break;
332
345
  }
333
- let block = chain.startBlock;
334
- let tmp$1;
335
- tmp$1 = block === "latest" ? 0 : block;
336
- return {
337
- chainId: chain.id,
346
+ let metrics_chainId = chain.id;
347
+ let metrics_firstEventBlockNumber = Stdlib_Option.flatMap(row, row => row.firstEventBlockNumber);
348
+ let metrics_latestProcessedBlock = progressBlockNumber === -1 ? undefined : progressBlockNumber;
349
+ let metrics_numEventsProcessed = Stdlib_Option.mapOr(row, 0, row => row.numEventsProcessed);
350
+ let metrics_latestFetchedBlockNumber = Primitive_int.max(progressBlockNumber, 0);
351
+ let metrics_addressesByContract = [];
352
+ let metrics_isReady = Stdlib_Option.isSome(timestampCaughtUpToHeadOrEndblock);
353
+ let metrics_progressBlockTime = Stdlib_Option.flatMap(row, row => row.progressBlockTime);
354
+ let metrics = {
355
+ chainId: metrics_chainId,
338
356
  poweredByHyperSync: tmp,
339
- firstEventBlockNumber: undefined,
340
- latestProcessedBlock: undefined,
341
- timestampCaughtUpToHeadOrEndblock: undefined,
342
- numEventsProcessed: 0,
343
- latestFetchedBlockNumber: 0,
344
- knownHeight: 0,
357
+ firstEventBlockNumber: metrics_firstEventBlockNumber,
358
+ latestProcessedBlock: metrics_latestProcessedBlock,
359
+ timestampCaughtUpToHeadOrEndblock: timestampCaughtUpToHeadOrEndblock,
360
+ numEventsProcessed: metrics_numEventsProcessed,
361
+ latestFetchedBlockNumber: metrics_latestFetchedBlockNumber,
362
+ knownHeight: sourceBlockNumber,
345
363
  numBatchesFetched: 0,
346
- startBlock: tmp$1,
347
- endBlock: chain.endBlock,
364
+ startBlock: startBlock,
365
+ endBlock: endBlock,
348
366
  numAddresses: 0,
349
- addressesByContract: [],
350
- isReady: false,
351
- sourceBlockNumber: 0,
352
- progressBlockNumber: -1,
367
+ addressesByContract: metrics_addressesByContract,
368
+ isReady: metrics_isReady,
369
+ sourceBlockNumber: sourceBlockNumber,
370
+ progressBlockNumber: progressBlockNumber,
353
371
  progressLatencyMs: undefined,
354
- progressBlockTime: undefined,
372
+ progressBlockTime: metrics_progressBlockTime,
355
373
  concurrency: 0,
356
374
  partitionsCount: 0,
357
375
  bufferSize: 0,
358
- bufferBlockNumber: -1,
376
+ bufferBlockNumber: progressBlockNumber,
359
377
  idleSeconds: 0,
360
378
  waitingForNewBlockSeconds: 0,
361
379
  queryingSeconds: 0,
@@ -370,18 +388,27 @@ function configuredChains(config) {
370
388
  rateLimitTimeMs: 0,
371
389
  rateLimitResetInMs: undefined
372
390
  };
391
+ let match$1 = Metrics.hasProcessedToEndblock(metrics);
392
+ if (!match$1) {
393
+ return metrics;
394
+ }
395
+ if (endBlock === undefined) {
396
+ return metrics;
397
+ }
398
+ let newrecord = {...metrics};
399
+ newrecord.knownHeight = endBlock;
400
+ return newrecord;
373
401
  });
374
402
  }
375
403
 
376
- function displayedSnapshots(running, config, empty) {
377
- let configured = configuredChains(config);
404
+ function displayedSnapshots(running, resumedChains, empty) {
378
405
  return running.map(r => {
379
406
  let snapshot = r.snapshot;
380
407
  if (snapshot !== undefined) {
381
408
  return snapshot;
382
409
  }
383
410
  let newrecord = {...empty};
384
- newrecord.chains = configured.filter(chain => r.worker.chainIds.includes(chain.chainId));
411
+ newrecord.chains = resumedChains.filter(chain => r.worker.chainIds.includes(chain.chainId));
385
412
  return newrecord;
386
413
  });
387
414
  }
@@ -402,7 +429,8 @@ async function run(config, logger, workers, reset) {
402
429
  maxConnections: Env.Db.maxConnections
403
430
  });
404
431
  let shouldUseTui = Tui.shouldUse(undefined, undefined);
405
- let holdRealtime = Persistence.getInitializedState(persistence).chains.some(chain => Stdlib_Option.isNone(chain.timestampCaughtUpToHeadOrEndblock));
432
+ let resumed = Persistence.getInitializedState(persistence).chains;
433
+ let holdRealtime = resumed.some(chain => Stdlib_Option.isNone(chain.timestampCaughtUpToHeadOrEndblock));
406
434
  let group = {
407
435
  running: [],
408
436
  stopping: false,
@@ -421,7 +449,8 @@ async function run(config, logger, workers, reset) {
421
449
  runtime
422
450
  ]))), config.isDev);
423
451
  if (shouldUseTui) {
424
- Tui.start(config, logger, () => merge(displayedSnapshots(group.running, config, merge([]))));
452
+ let resumedChains$1 = resumedChains(config, resumed);
453
+ Tui.start(config, logger, () => merge(displayedSnapshots(group.running, resumedChains$1, merge([]))));
425
454
  }
426
455
  process.on("SIGTERM", () => stop(group));
427
456
  process.on("SIGINT", () => stop(group));
@@ -465,7 +494,7 @@ export {
465
494
  awaitExit,
466
495
  isRunAtHead,
467
496
  releaseIfAtHead,
468
- configuredChains,
497
+ resumedChains,
469
498
  displayedSnapshots,
470
499
  run,
471
500
  }
@@ -0,0 +1,107 @@
1
+ // The writes one round of a synchronous handler has made. A round that
2
+ // suspends is replayed from the top, so its writes are held here rather than
3
+ // applied: the replay has to see the store exactly as the first round did, or a
4
+ // read-modify-write lands once per round.
5
+
6
+ // A Map rather than a dict: every round makes a fresh one keyed by ids no
7
+ // other round shares, and a dict would give each of them its own hidden class.
8
+ type table = {
9
+ entityConfig: Internal.entityConfig,
10
+ scope: Internal.chainScope,
11
+ changes: Map.t<string, Change.t<Internal.entity>>,
12
+ }
13
+
14
+ // A handler runs on one chain, so an entity's scope is fixed for the whole
15
+ // round and the entity name is enough to key its table.
16
+ type t = dict<table>
17
+
18
+ let make = (): t => Dict.make()
19
+
20
+ let record = (writes: t, ~entityConfig: Internal.entityConfig, ~scope, change) => {
21
+ let table = switch writes->Utils.Dict.dangerouslyGetNonOption(entityConfig.name) {
22
+ | Some(table) => table
23
+ | None =>
24
+ let table = {entityConfig, scope, changes: Map.make()}
25
+ writes->Dict.set(entityConfig.name, table)
26
+ table
27
+ }
28
+ table.changes->Map.set(entityConfig.table.entityIdToKey(change->Change.getEntityId), change)
29
+ }
30
+
31
+ let changesOf = (writes: t, ~entityConfig: Internal.entityConfig) =>
32
+ switch writes->Utils.Dict.dangerouslyGetNonOption(entityConfig.name) {
33
+ | Some({changes}) => Some(changes)
34
+ | None => None
35
+ }
36
+
37
+ // `Some(None)` is a delete this round made: the entity is known not to exist.
38
+ let getById = (writes: t, ~entityConfig: Internal.entityConfig, ~entityId: string) =>
39
+ switch writes->changesOf(~entityConfig) {
40
+ | Some(changes) =>
41
+ changes
42
+ ->Map.get(entityConfig.table.entityIdToKey(entityId->EntityId.unsafeOfString))
43
+ ->Option.map(InMemoryTable.Entity.mapChangeToEntity)
44
+ | None => None
45
+ }
46
+
47
+ // What the store answered, as it reads once this round's writes land: a row
48
+ // the round rewrote is re-tested against the filter, and one it created joins.
49
+ let overlayFilter = (
50
+ writes: t,
51
+ entities: array<Internal.entity>,
52
+ ~entityConfig: Internal.entityConfig,
53
+ ~filter: EntityFilter.t,
54
+ ) =>
55
+ switch writes->changesOf(~entityConfig) {
56
+ | None => entities
57
+ | Some(changes) =>
58
+ let matches = filter->EntityFilter.makeMatcher(~table=entityConfig.table)
59
+ let untouched =
60
+ entities->Array.filter(entity =>
61
+ !(
62
+ changes->Map.has(
63
+ entityConfig.table.entityIdToKey(
64
+ (entity->(Utils.magic: Internal.entity => {"id": EntityId.t}))["id"],
65
+ ),
66
+ )
67
+ )
68
+ )
69
+ let written = []
70
+ changes->Map.forEach(change =>
71
+ switch change->InMemoryTable.Entity.mapChangeToEntity {
72
+ | Some(entity) if matches(entity) => written->Array.push(entity)->ignore
73
+ | _ => ()
74
+ }
75
+ )
76
+ untouched->Array.concat(written)
77
+ }
78
+
79
+ // How a change lands in the in-memory store, whether written directly or
80
+ // committed at the end of a round.
81
+ let write = (indexerState, ~entityConfig: Internal.entityConfig, ~scope, change) => {
82
+ switch change {
83
+ | Change.Set({entityId}) =>
84
+ PreloadLookahead.onSet(
85
+ ~entityName=entityConfig.name,
86
+ ~scope,
87
+ ~entityId=entityConfig.table.entityIdToKey(entityId),
88
+ )
89
+ | Delete(_) => ()
90
+ }
91
+ indexerState
92
+ ->InMemoryStore.getInMemTable(~entityConfig, ~scope)
93
+ ->InMemoryTable.Entity.set(
94
+ ~committedCheckpointId=indexerState->IndexerState.committedCheckpointIdFor(~scope),
95
+ change,
96
+ )
97
+ }
98
+
99
+ let forEachChange = (writes: t, fn) =>
100
+ writes->Utils.Dict.forEach(({entityConfig, scope, changes}) =>
101
+ changes->Map.forEach(change => fn(~entityConfig, ~scope, change))
102
+ )
103
+
104
+ let commit = (writes: t, ~indexerState) =>
105
+ writes->Utils.Dict.forEach(({entityConfig, scope, changes}) =>
106
+ changes->Map.forEach(change => indexerState->write(~entityConfig, ~scope, change))
107
+ )
@@ -0,0 +1,98 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "./Utils.res.mjs";
4
+ import * as EntityFilter from "./db/EntityFilter.res.mjs";
5
+ import * as IndexerState from "./IndexerState.res.mjs";
6
+ import * as InMemoryStore from "./InMemoryStore.res.mjs";
7
+ import * as InMemoryTable from "./InMemoryTable.res.mjs";
8
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
9
+ import * as PreloadLookahead from "./PreloadLookahead.res.mjs";
10
+
11
+ function make() {
12
+ return {};
13
+ }
14
+
15
+ function record(writes, entityConfig, scope, change) {
16
+ let table = writes[entityConfig.name];
17
+ let table$1;
18
+ if (table !== undefined) {
19
+ table$1 = table;
20
+ } else {
21
+ let table_changes = new Map();
22
+ let table$2 = {
23
+ entityConfig: entityConfig,
24
+ scope: scope,
25
+ changes: table_changes
26
+ };
27
+ writes[entityConfig.name] = table$2;
28
+ table$1 = table$2;
29
+ }
30
+ table$1.changes.set(entityConfig.table.entityIdToKey(change.entityId), change);
31
+ }
32
+
33
+ function changesOf(writes, entityConfig) {
34
+ let match = writes[entityConfig.name];
35
+ if (match !== undefined) {
36
+ return match.changes;
37
+ }
38
+ }
39
+
40
+ function getById(writes, entityConfig, entityId) {
41
+ let changes = changesOf(writes, entityConfig);
42
+ if (changes !== undefined) {
43
+ return Stdlib_Option.map(changes.get(entityConfig.table.entityIdToKey(entityId)), InMemoryTable.Entity.mapChangeToEntity);
44
+ }
45
+ }
46
+
47
+ function overlayFilter(writes, entities, entityConfig, filter) {
48
+ let changes = changesOf(writes, entityConfig);
49
+ if (changes === undefined) {
50
+ return entities;
51
+ }
52
+ let matches = EntityFilter.makeMatcher(filter, entityConfig.table);
53
+ let untouched = entities.filter(entity => !changes.has(entityConfig.table.entityIdToKey(entity.id)));
54
+ let written = [];
55
+ changes.forEach(change => {
56
+ let entity = InMemoryTable.Entity.mapChangeToEntity(change);
57
+ if (entity !== undefined && matches(entity)) {
58
+ written.push(entity);
59
+ return;
60
+ }
61
+ });
62
+ return untouched.concat(written);
63
+ }
64
+
65
+ function write(indexerState, entityConfig, scope, change) {
66
+ if (change.type === "SET") {
67
+ PreloadLookahead.onSet(entityConfig.name, scope, entityConfig.table.entityIdToKey(change.entityId));
68
+ }
69
+ InMemoryTable.Entity.set(InMemoryStore.getInMemTable(indexerState, entityConfig, scope), IndexerState.committedCheckpointIdFor(indexerState, scope), change);
70
+ }
71
+
72
+ function forEachChange(writes, fn) {
73
+ Utils.Dict.forEach(writes, param => {
74
+ let scope = param.scope;
75
+ let entityConfig = param.entityConfig;
76
+ param.changes.forEach(change => fn(entityConfig, scope, change));
77
+ });
78
+ }
79
+
80
+ function commit(writes, indexerState) {
81
+ Utils.Dict.forEach(writes, param => {
82
+ let scope = param.scope;
83
+ let entityConfig = param.entityConfig;
84
+ param.changes.forEach(change => write(indexerState, entityConfig, scope, change));
85
+ });
86
+ }
87
+
88
+ export {
89
+ make,
90
+ record,
91
+ changesOf,
92
+ getById,
93
+ overlayFilter,
94
+ write,
95
+ forEachChange,
96
+ commit,
97
+ }
98
+ /* Utils Not a pure module */