envio 3.12.1 → 3.13.0-rc.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 (103) hide show
  1. package/package.json +6 -8
  2. package/src/BatchProcessing.res +15 -14
  3. package/src/BatchProcessing.res.mjs +8 -15
  4. package/src/Bin.res +24 -17
  5. package/src/Bin.res.mjs +5 -0
  6. package/src/ChainFetching.res +18 -24
  7. package/src/ChainFetching.res.mjs +14 -15
  8. package/src/ChainState.res +103 -38
  9. package/src/ChainState.res.mjs +79 -22
  10. package/src/ChainState.resi +14 -2
  11. package/src/Config.res +32 -0
  12. package/src/Config.res.mjs +24 -0
  13. package/src/Core.res +4 -0
  14. package/src/Core.res.mjs +4 -0
  15. package/src/CrossChainState.res +109 -11
  16. package/src/CrossChainState.res.mjs +71 -7
  17. package/src/CrossChainState.resi +11 -1
  18. package/src/Env.res +4 -0
  19. package/src/ErrorHandling.res +15 -4
  20. package/src/ErrorHandling.res.mjs +16 -5
  21. package/src/FinalizeBackfill.res +10 -4
  22. package/src/FinalizeBackfill.res.mjs +5 -3
  23. package/src/HandlerRegister.res +0 -37
  24. package/src/HandlerRegister.res.mjs +0 -18
  25. package/src/IndexerLoop.res +2 -0
  26. package/src/IndexerLoop.res.mjs +1 -0
  27. package/src/IndexerState.res +43 -1
  28. package/src/IndexerState.res.mjs +48 -4
  29. package/src/IndexerState.resi +11 -0
  30. package/src/Main.res +128 -268
  31. package/src/Main.res.mjs +27 -153
  32. package/src/Metrics.res +268 -102
  33. package/src/Metrics.res.mjs +227 -48
  34. package/src/Persistence.res +30 -2
  35. package/src/Persistence.res.mjs +12 -3
  36. package/src/PgStorage.res +19 -11
  37. package/src/PgStorage.res.mjs +13 -10
  38. package/src/Rollback.res +3 -3
  39. package/src/Server.res +178 -0
  40. package/src/Server.res.mjs +143 -0
  41. package/src/SimulateItems.res +1 -1
  42. package/src/SimulateItems.res.mjs +1 -1
  43. package/src/Supervisor.res +542 -0
  44. package/src/Supervisor.res.mjs +455 -0
  45. package/src/TestIndexer.res +1 -1
  46. package/src/TestIndexer.res.mjs +2 -2
  47. package/src/Worker.res +101 -0
  48. package/src/Worker.res.mjs +81 -0
  49. package/src/bindings/NodeJs.res +50 -0
  50. package/src/bindings/NodeJs.res.mjs +8 -1
  51. package/src/db/InternalTable.res +8 -1
  52. package/src/db/InternalTable.res.mjs +5 -1
  53. package/src/sources/AddressSet.res +5 -3
  54. package/src/sources/AddressStore.res +19 -11
  55. package/src/sources/AddressStore.res.mjs +2 -7
  56. package/src/sources/BlockStore.res +10 -9
  57. package/src/sources/BlockStore.res.mjs +4 -4
  58. package/src/sources/ChainSources.res +4 -0
  59. package/src/sources/ChainSources.res.mjs +2 -2
  60. package/src/sources/EvmChain.res +4 -0
  61. package/src/sources/EvmChain.res.mjs +3 -1
  62. package/src/sources/EvmEventItem.res +56 -0
  63. package/src/sources/EvmEventItem.res.mjs +32 -0
  64. package/src/sources/EvmHyperSyncSource.res +7 -37
  65. package/src/sources/EvmHyperSyncSource.res.mjs +8 -29
  66. package/src/sources/EvmRpcClient.res +41 -59
  67. package/src/sources/EvmRpcClient.res.mjs +4 -54
  68. package/src/sources/EvmRpcWs.res +4 -1
  69. package/src/sources/EvmRpcWs.res.mjs +6 -2
  70. package/src/sources/FuelHyperSyncSource.res +6 -4
  71. package/src/sources/FuelHyperSyncSource.res.mjs +7 -9
  72. package/src/sources/HeightFeed.res +7 -1
  73. package/src/sources/HeightFeed.res.mjs +9 -7
  74. package/src/sources/HyperSyncClient.res +1 -14
  75. package/src/sources/RequestStat.res +7 -0
  76. package/src/sources/RequestStat.res.mjs +14 -1
  77. package/src/sources/RpcSource.res +100 -1043
  78. package/src/sources/RpcSource.res.mjs +81 -1056
  79. package/src/sources/SimulateSource.res +2 -5
  80. package/src/sources/SimulateSource.res.mjs +2 -3
  81. package/src/sources/Source.res +34 -12
  82. package/src/sources/Source.res.mjs +11 -0
  83. package/src/sources/SourceManager.res +111 -31
  84. package/src/sources/SourceManager.res.mjs +65 -31
  85. package/src/sources/SourceManager.resi +4 -0
  86. package/src/sources/StartBlockResolver.res +8 -5
  87. package/src/sources/StartBlockResolver.res.mjs +4 -2
  88. package/src/sources/SvmHyperSyncSource.res +4 -2
  89. package/src/sources/SvmHyperSyncSource.res.mjs +4 -6
  90. package/src/sources/TransactionStore.res +9 -6
  91. package/src/sources/TransactionStore.res.mjs +2 -2
  92. package/src/tui/Tui.res +10 -0
  93. package/src/tui/Tui.res.mjs +15 -0
  94. package/src/tui/components/SyncETA.res +12 -6
  95. package/src/tui/components/SyncETA.res.mjs +12 -8
  96. package/src/LazyLoader.res +0 -135
  97. package/src/LazyLoader.res.mjs +0 -118
  98. package/src/bindings/SDSL.res +0 -12
  99. package/src/bindings/SDSL.res.mjs +0 -9
  100. package/src/bindings/Yargs.res +0 -8
  101. package/src/bindings/Yargs.res.mjs +0 -2
  102. package/src/sources/Rpc.res +0 -185
  103. package/src/sources/Rpc.res.mjs +0 -183
@@ -45,6 +45,8 @@ let start = (state: IndexerState.t) => {
45
45
  launch(state, () => FinalizeBackfill.repairSchemaIndexes(state))
46
46
  }
47
47
 
48
+ state->IndexerState.bindScheduleProcessing(scheduleProcessing)
49
+
48
50
  scheduleFetch()
49
51
  scheduleProcessing()
50
52
  }
@@ -42,6 +42,7 @@ function start(state) {
42
42
  work();
43
43
  }
44
44
  }
45
+ IndexerState.bindScheduleProcessing(state, scheduleProcessing);
45
46
  scheduleFetch();
46
47
  scheduleProcessing();
47
48
  }
@@ -115,6 +115,10 @@ type t = {
115
115
  // waitForNewBlock waiter is bound to the old, pre-realtime source). A fetch
116
116
  // response or waiter carrying an older epoch than this is discarded.
117
117
  mutable epoch: int,
118
+ // The loop's one door in from outside it: IndexerLoop owns scheduling and
119
+ // wires this when it starts, so an event the loop can't see for itself can
120
+ // still make it re-evaluate. A no-op before then.
121
+ mutable scheduleProcessing: unit => unit,
118
122
  // None off the simulate path.
119
123
  simulateDeadInputTracker: option<SimulateDeadInputTracker.t>,
120
124
  // --- Metric counters, rendered by Metrics at scrape time. ---
@@ -141,6 +145,7 @@ let make = (
141
145
  ~chainStates: dict<ChainState.t>,
142
146
  ~isRealtime: bool,
143
147
  ~targetBufferSize=CrossChainState.calculateTargetBufferSize(),
148
+ ~holdRealtime=false,
144
149
  ~committedFrontier=Frontier.empty(),
145
150
  ~isDevelopmentMode=false,
146
151
  ~shouldUseTui=false,
@@ -180,11 +185,17 @@ let make = (
180
185
  chainMetaDirty: false,
181
186
  chainMetaThrottler,
182
187
  isProcessing: false,
183
- crossChainState: CrossChainState.make(~chainStates, ~isRealtime, ~targetBufferSize),
188
+ crossChainState: CrossChainState.make(
189
+ ~chainStates,
190
+ ~isRealtime,
191
+ ~targetBufferSize,
192
+ ~holdRealtime,
193
+ ),
184
194
  indexerStartTime: Date.make(),
185
195
  indexerStartTimeRef: Performance.now(),
186
196
  rollbackState: NoRollback,
187
197
  lastPrunedAtMillis: Dict.make(),
198
+ scheduleProcessing: () => (),
188
199
  loadManager: LoadManager.make(),
189
200
  keepProcessAlive: isDevelopmentMode || shouldUseTui,
190
201
  exitAfterFirstEventBlock,
@@ -227,6 +238,9 @@ let makeFromDbState = (
227
238
  ~exitAfterFirstEventBlock=false,
228
239
  ~reducedPollingInterval=?,
229
240
  ~targetBufferSize=CrossChainState.calculateTargetBufferSize(),
241
+ // A process driving part of a split run waits for its supervisor before
242
+ // entering the reorg threshold or switching to realtime.
243
+ ~holdRealtime=false,
230
244
  ~onError,
231
245
  ~onExit=?,
232
246
  ) => {
@@ -274,6 +288,7 @@ let makeFromDbState = (
274
288
  ~chainStates,
275
289
  ~isRealtime,
276
290
  ~targetBufferSize,
291
+ ~holdRealtime,
277
292
  ~committedFrontier=initialState.checkpointFrontier,
278
293
  ~isDevelopmentMode,
279
294
  ~shouldUseTui,
@@ -500,11 +515,37 @@ let isFinalizingIndexes = (state: t) =>
500
515
  state.crossChainState->CrossChainState.isCaughtUp &&
501
516
  !(state.crossChainState->CrossChainState.isRealtime)
502
517
 
518
+ // The FinalizingIndexes phase is the transition a held process waits on: it
519
+ // ends with `ready_at` committed and the indexer realtime.
520
+ let shouldFinalizeIndexes = (state: t) =>
521
+ state->isFinalizingIndexes && !(state.crossChainState->CrossChainState.isHoldingRealtime)
522
+
503
523
  let markCaughtUpIfSettled = (state: t) =>
504
524
  state.crossChainState->CrossChainState.markCaughtUpIfSettled
505
525
 
526
+ let isReadyToEnterReorgThreshold = (state: t, ~batch) =>
527
+ state.crossChainState->CrossChainState.isReadyToEnterReorgThreshold(~batch)
528
+
529
+ let bindScheduleProcessing = (state: t, scheduleProcessing) =>
530
+ state.scheduleProcessing = scheduleProcessing
531
+
532
+ // A process still waiting on its supervisor owes the schema the indexes its
533
+ // chains deferred, so reaching every end block doesn't make it done.
534
+ let isHoldingRealtime = (state: t) => state.crossChainState->CrossChainState.isHoldingRealtime
535
+
536
+ let hasArrivedAtHead = (state: t) => state.crossChainState->CrossChainState.hasArrivedAtHead
537
+
538
+ let releaseRealtime = (state: t) => {
539
+ state.crossChainState->CrossChainState.releaseRealtime
540
+ // Every chain is parked at the head with no batch coming, so nothing would
541
+ // notice the hold is gone without a pass through processing.
542
+ state.scheduleProcessing()
543
+ }
544
+
506
545
  let markReady = (state: t, ~readyAt) => state.crossChainState->CrossChainState.markReady(~readyAt)
507
546
 
547
+ let reportFinished = (state: t) => state.crossChainState->CrossChainState.reportFinished
548
+
508
549
  let rollbackState = (state: t) => state.rollbackState
509
550
  let indexerStartTime = (state: t) => state.indexerStartTime
510
551
  let loadManager = (state: t) => state.loadManager
@@ -572,6 +613,7 @@ let toMetrics = (state: t): Metrics.t => {
572
613
  elapsedSeconds: state.indexerStartTimeRef->Performance.secondsSince,
573
614
  targetBufferSize: state.crossChainState->CrossChainState.targetBufferSize,
574
615
  isInReorgThreshold: state.crossChainState->CrossChainState.isInReorgThreshold,
616
+ hasArrivedAtHead: state.crossChainState->CrossChainState.hasArrivedAtHead,
575
617
  rollbackEnabled: state.config.shouldRollbackOnReorg,
576
618
  maxBatchSize: state.config.batchSize,
577
619
  preloadSeconds: state.preloadSeconds,
@@ -24,8 +24,9 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
24
24
  import * as CheckpointSequence from "./db/CheckpointSequence.res.mjs";
25
25
  import * as SimulateDeadInputTracker from "./SimulateDeadInputTracker.res.mjs";
26
26
 
27
- function make(config, persistence, chainStates, isRealtime, targetBufferSizeOpt, committedFrontierOpt, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, onError, onExit) {
27
+ function make(config, persistence, chainStates, isRealtime, targetBufferSizeOpt, holdRealtimeOpt, committedFrontierOpt, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, onError, onExit) {
28
28
  let targetBufferSize = targetBufferSizeOpt !== undefined ? targetBufferSizeOpt : CrossChainState.calculateTargetBufferSize();
29
+ let holdRealtime = holdRealtimeOpt !== undefined ? holdRealtimeOpt : false;
29
30
  let committedFrontier = committedFrontierOpt !== undefined ? committedFrontierOpt : Frontier.empty();
30
31
  let isDevelopmentMode = isDevelopmentModeOpt !== undefined ? isDevelopmentModeOpt : false;
31
32
  let shouldUseTui = shouldUseTuiOpt !== undefined ? shouldUseTuiOpt : false;
@@ -54,7 +55,7 @@ function make(config, persistence, chainStates, isRealtime, targetBufferSizeOpt,
54
55
  chainMetaDirty: false,
55
56
  chainMetaThrottler: chainMetaThrottler,
56
57
  isProcessing: false,
57
- crossChainState: CrossChainState.make(chainStates, isRealtime, targetBufferSize),
58
+ crossChainState: CrossChainState.make(chainStates, isRealtime, targetBufferSize, holdRealtime),
58
59
  rollbackState: "NoRollback",
59
60
  indexerStartTime: new Date(),
60
61
  indexerStartTimeRef: Performance.now(),
@@ -66,6 +67,7 @@ function make(config, persistence, chainStates, isRealtime, targetBufferSizeOpt,
66
67
  onExit: onExit,
67
68
  isStopped: false,
68
69
  epoch: 0,
70
+ scheduleProcessing: () => {},
69
71
  simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config),
70
72
  preloadSeconds: 0,
71
73
  processingSeconds: 0,
@@ -82,11 +84,12 @@ function make(config, persistence, chainStates, isRealtime, targetBufferSizeOpt,
82
84
  };
83
85
  }
84
86
 
85
- function makeFromDbState(config, persistence, initialState, registrationsByChainId, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, reducedPollingInterval, targetBufferSizeOpt, onError, onExit) {
87
+ function makeFromDbState(config, persistence, initialState, registrationsByChainId, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, reducedPollingInterval, targetBufferSizeOpt, holdRealtimeOpt, onError, onExit) {
86
88
  let isDevelopmentMode = isDevelopmentModeOpt !== undefined ? isDevelopmentModeOpt : false;
87
89
  let shouldUseTui = shouldUseTuiOpt !== undefined ? shouldUseTuiOpt : false;
88
90
  let exitAfterFirstEventBlock = exitAfterFirstEventBlockOpt !== undefined ? exitAfterFirstEventBlockOpt : false;
89
91
  let targetBufferSize = targetBufferSizeOpt !== undefined ? targetBufferSizeOpt : CrossChainState.calculateTargetBufferSize();
92
+ let holdRealtime = holdRealtimeOpt !== undefined ? holdRealtimeOpt : false;
90
93
  let isInReorgThreshold = initialState.cleanRun ? false : initialState.chains.some(resumedChainState => {
91
94
  let progressBlockNumber = resumedChainState.progressBlockNumber;
92
95
  let sourceBlockNumber = resumedChainState.sourceBlockNumber;
@@ -104,7 +107,7 @@ function makeFromDbState(config, persistence, initialState, registrationsByChain
104
107
  let chainConfig = ChainMap.get(config.chainMap, chainId);
105
108
  chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, initialState.contractMapping, registrationsByChainId, reducedPollingInterval);
106
109
  });
107
- let state = make(config, persistence, chainStates, isRealtime, targetBufferSize, initialState.checkpointFrontier, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError, onExit);
110
+ let state = make(config, persistence, chainStates, isRealtime, targetBufferSize, holdRealtime, initialState.checkpointFrontier, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError, onExit);
108
111
  CrossChainState.markCaughtUpOnResume(state.crossChainState);
109
112
  Utils.Dict.forEach(initialState.cache, param => {
110
113
  let count = param.count;
@@ -350,14 +353,47 @@ function isFinalizingIndexes(state) {
350
353
  }
351
354
  }
352
355
 
356
+ function shouldFinalizeIndexes(state) {
357
+ if (isFinalizingIndexes(state)) {
358
+ return !CrossChainState.isHoldingRealtime(state.crossChainState);
359
+ } else {
360
+ return false;
361
+ }
362
+ }
363
+
353
364
  function markCaughtUpIfSettled(state) {
354
365
  CrossChainState.markCaughtUpIfSettled(state.crossChainState);
355
366
  }
356
367
 
368
+ function isReadyToEnterReorgThreshold(state, batch) {
369
+ return CrossChainState.isReadyToEnterReorgThreshold(state.crossChainState, batch);
370
+ }
371
+
372
+ function bindScheduleProcessing(state, scheduleProcessing) {
373
+ state.scheduleProcessing = scheduleProcessing;
374
+ }
375
+
376
+ function isHoldingRealtime(state) {
377
+ return CrossChainState.isHoldingRealtime(state.crossChainState);
378
+ }
379
+
380
+ function hasArrivedAtHead(state) {
381
+ return CrossChainState.hasArrivedAtHead(state.crossChainState);
382
+ }
383
+
384
+ function releaseRealtime(state) {
385
+ CrossChainState.releaseRealtime(state.crossChainState);
386
+ state.scheduleProcessing();
387
+ }
388
+
357
389
  function markReady(state, readyAt) {
358
390
  CrossChainState.markReady(state.crossChainState, readyAt);
359
391
  }
360
392
 
393
+ function reportFinished(state) {
394
+ CrossChainState.reportFinished(state.crossChainState);
395
+ }
396
+
361
397
  function rollbackState(state) {
362
398
  return state.rollbackState;
363
399
  }
@@ -447,6 +483,7 @@ function toMetrics(state) {
447
483
  elapsedSeconds: Performance.secondsSince(state.indexerStartTimeRef),
448
484
  targetBufferSize: CrossChainState.targetBufferSize(state.crossChainState),
449
485
  isInReorgThreshold: CrossChainState.isInReorgThreshold(state.crossChainState),
486
+ hasArrivedAtHead: CrossChainState.hasArrivedAtHead(state.crossChainState),
450
487
  rollbackEnabled: state.config.shouldRollbackOnReorg,
451
488
  maxBatchSize: state.config.batchSize,
452
489
  preloadSeconds: state.preloadSeconds,
@@ -844,7 +881,14 @@ export {
844
881
  isRealtime,
845
882
  isFinalizingIndexes,
846
883
  markCaughtUpIfSettled,
884
+ isReadyToEnterReorgThreshold,
885
+ shouldFinalizeIndexes,
886
+ bindScheduleProcessing,
887
+ isHoldingRealtime,
888
+ hasArrivedAtHead,
889
+ releaseRealtime,
847
890
  markReady,
891
+ reportFinished,
848
892
  rollbackState,
849
893
  indexerStartTime,
850
894
  loadManager,
@@ -16,6 +16,7 @@ let make: (
16
16
  ~chainStates: dict<ChainState.t>,
17
17
  ~isRealtime: bool,
18
18
  ~targetBufferSize: int=?,
19
+ ~holdRealtime: bool=?,
19
20
  ~committedFrontier: Frontier.t=?,
20
21
  ~isDevelopmentMode: bool=?,
21
22
  ~shouldUseTui: bool=?,
@@ -34,6 +35,7 @@ let makeFromDbState: (
34
35
  ~exitAfterFirstEventBlock: bool=?,
35
36
  ~reducedPollingInterval: int=?,
36
37
  ~targetBufferSize: int=?,
38
+ ~holdRealtime: bool=?,
37
39
  ~onError: ErrorHandling.t => unit,
38
40
  ~onExit: unit => unit=?,
39
41
  ) => t
@@ -93,7 +95,16 @@ let shouldSaveHistory: t => dict<bool>
93
95
  let isRealtime: t => bool
94
96
  let isFinalizingIndexes: t => bool
95
97
  let markCaughtUpIfSettled: t => unit
98
+ let isReadyToEnterReorgThreshold: (t, ~batch: Batch.t) => bool
99
+ let shouldFinalizeIndexes: t => bool
100
+ // Wires the loop's way back in. IndexerLoop calls this as it starts.
101
+ let bindScheduleProcessing: (t, unit => unit) => unit
102
+ let isHoldingRealtime: t => bool
103
+ let hasArrivedAtHead: t => bool
104
+ // The supervisor's go-ahead for a process driving part of a split run.
105
+ let releaseRealtime: t => unit
96
106
  let markReady: (t, ~readyAt: Date.t) => unit
107
+ let reportFinished: t => unit
97
108
  let rollbackState: t => rollbackState
98
109
  let indexerStartTime: t => Date.t
99
110
  let loadManager: t => LoadManager.t