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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.12.1",
3
+ "version": "3.13.0-rc.0",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -49,11 +49,9 @@
49
49
  "@fuel-ts/utils": "0.96.1",
50
50
  "bignumber.js": "9.3.1",
51
51
  "eventsource": "4.1.0",
52
- "js-sdsl": "4.4.2",
53
52
  "express": "4.19.2",
54
53
  "pino": "10.3.1",
55
54
  "pino-pretty": "13.1.3",
56
- "yargs": "17.7.2",
57
55
  "@rescript/runtime": "12.2.0",
58
56
  "rescript-schema": "9.5.1",
59
57
  "viem": "2.54.0",
@@ -68,10 +66,10 @@
68
66
  "tsx": "4.21.0"
69
67
  },
70
68
  "optionalDependencies": {
71
- "envio-linux-x64": "3.12.1",
72
- "envio-linux-x64-musl": "3.12.1",
73
- "envio-linux-arm64": "3.12.1",
74
- "envio-darwin-x64": "3.12.1",
75
- "envio-darwin-arm64": "3.12.1"
69
+ "envio-linux-x64": "3.13.0-rc.0",
70
+ "envio-linux-x64-musl": "3.13.0-rc.0",
71
+ "envio-linux-arm64": "3.13.0-rc.0",
72
+ "envio-darwin-x64": "3.13.0-rc.0",
73
+ "envio-darwin-arm64": "3.13.0-rc.0"
76
74
  }
77
75
  }
@@ -69,18 +69,15 @@ and processNextBatch = async (state: IndexerState.t, ~scheduleFetch): unit => {
69
69
  let isInReorgThresholdBeforeUpdate = state->IndexerState.isInReorgThreshold
70
70
  let isRealtimeBeforeUpdate = state->IndexerState.isRealtime
71
71
 
72
- let batch = state->IndexerState.createBatch(~batchSizeTarget=(state->IndexerState.config).batchSize)
72
+ let batch =
73
+ state->IndexerState.createBatch(~batchSizeTarget=(state->IndexerState.config).batchSize)
73
74
 
74
75
  let progressedChainsById = batch.progressedChainsById
75
76
 
76
77
  let isBelowReorgThreshold =
77
78
  !isInReorgThresholdBeforeUpdate && (state->IndexerState.config).shouldRollbackOnReorg
78
79
  let shouldEnterReorgThreshold =
79
- isBelowReorgThreshold &&
80
- state
81
- ->IndexerState.chainStates
82
- ->Dict.valuesToArray
83
- ->Array.every(cs => cs->ChainState.isReadyToEnterReorgThresholdAfterBatch(~batch))
80
+ isBelowReorgThreshold && state->IndexerState.isReadyToEnterReorgThreshold(~batch)
84
81
 
85
82
  if shouldEnterReorgThreshold {
86
83
  IndexerState.enterReorgThreshold(state)
@@ -95,7 +92,7 @@ and processNextBatch = async (state: IndexerState.t, ~scheduleFetch): unit => {
95
92
  // finalizing resumes exactly here: it still owes the schema its deferred
96
93
  // indexes, and no batch will ever come along to notice.
97
94
  state->IndexerState.markCaughtUpIfSettled
98
- if state->IndexerState.isFinalizingIndexes {
95
+ if state->IndexerState.shouldFinalizeIndexes {
99
96
  await FinalizeBackfill.run(state)
100
97
  }
101
98
 
@@ -109,9 +106,9 @@ and processNextBatch = async (state: IndexerState.t, ~scheduleFetch): unit => {
109
106
  }
110
107
 
111
108
  // When resuming from persisted state, all events may already be processed.
109
+ state->IndexerState.reportFinished
112
110
  if EventProcessing.allChainsEventsProcessedToEndblock(state->IndexerState.chainStates) {
113
- Logging.info("All chains are caught up to end blocks.")
114
- if !(state->IndexerState.keepProcessAlive) {
111
+ if !(state->IndexerState.keepProcessAlive) && !(state->IndexerState.isHoldingRealtime) {
115
112
  await ExitOnCaughtUp.run(state)
116
113
  }
117
114
  }
@@ -162,11 +159,14 @@ and processNextBatch = async (state: IndexerState.t, ~scheduleFetch): unit => {
162
159
  // Can safely reset rollback state, since overwrite is not possible.
163
160
  state->IndexerState.clearRollback
164
161
  state->IndexerState.applyBatchProgress(~batch)
162
+ // Before the finalize below, so a chain says where it finished ahead of
163
+ // the process saying what it does about that.
164
+ state->IndexerState.reportFinished
165
165
 
166
166
  // Backfilling → FinalizingIndexes → Ready. Awaiting here holds the
167
167
  // processing loop for the whole finalize, which is what pauses
168
168
  // processing while the indexes are built.
169
- if state->IndexerState.isFinalizingIndexes {
169
+ if state->IndexerState.shouldFinalizeIndexes {
170
170
  await FinalizeBackfill.run(state)
171
171
  }
172
172
 
@@ -182,11 +182,12 @@ and processNextBatch = async (state: IndexerState.t, ~scheduleFetch): unit => {
182
182
  let allCaughtUp = EventProcessing.allChainsEventsProcessedToEndblock(
183
183
  state->IndexerState.chainStates,
184
184
  )
185
- if allCaughtUp {
186
- Logging.info("All chains are caught up to end blocks.")
187
- }
188
185
 
189
- if allCaughtUp && !(state->IndexerState.keepProcessAlive) {
186
+ if (
187
+ allCaughtUp &&
188
+ !(state->IndexerState.keepProcessAlive) &&
189
+ !(state->IndexerState.isHoldingRealtime)
190
+ ) {
190
191
  await ExitOnCaughtUp.run(state)
191
192
  } else if (
192
193
  // In auto-exit mode, error if all chains reached head with no events found
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Utils from "./Utils.res.mjs";
4
- import * as Logging from "./Logging.res.mjs";
5
4
  import * as ChainState from "./ChainState.res.mjs";
6
5
  import * as IndexerState from "./IndexerState.res.mjs";
7
6
  import * as ChainMetadata from "./ChainMetadata.res.mjs";
@@ -26,7 +25,7 @@ async function processNextBatch(state, scheduleFetch) {
26
25
  let batch = IndexerState.createBatch(state, IndexerState.config(state).batchSize);
27
26
  let progressedChainsById = batch.progressedChainsById;
28
27
  let isBelowReorgThreshold = !isInReorgThresholdBeforeUpdate && IndexerState.config(state).shouldRollbackOnReorg;
29
- let shouldEnterReorgThreshold = isBelowReorgThreshold && Object.values(IndexerState.chainStates(state)).every(cs => ChainState.isReadyToEnterReorgThresholdAfterBatch(cs, batch));
28
+ let shouldEnterReorgThreshold = isBelowReorgThreshold && IndexerState.isReadyToEnterReorgThreshold(state, batch);
30
29
  if (shouldEnterReorgThreshold) {
31
30
  IndexerState.enterReorgThreshold(state);
32
31
  }
@@ -35,20 +34,16 @@ async function processNextBatch(state, scheduleFetch) {
35
34
  scheduleFetch();
36
35
  }
37
36
  IndexerState.markCaughtUpIfSettled(state);
38
- if (IndexerState.isFinalizingIndexes(state)) {
37
+ if (IndexerState.shouldFinalizeIndexes(state)) {
39
38
  await FinalizeBackfill.run(state);
40
39
  }
41
40
  if (!isRealtimeBeforeUpdate && IndexerState.isRealtime(state)) {
42
41
  IndexerState.invalidateInflight(state);
43
42
  scheduleFetch();
44
43
  }
45
- if (EventProcessing.allChainsEventsProcessedToEndblock(IndexerState.chainStates(state))) {
46
- Logging.info("All chains are caught up to end blocks.");
47
- if (!IndexerState.keepProcessAlive(state)) {
48
- return await ExitOnCaughtUp.run(state);
49
- } else {
50
- return;
51
- }
44
+ IndexerState.reportFinished(state);
45
+ if (EventProcessing.allChainsEventsProcessedToEndblock(IndexerState.chainStates(state)) && !IndexerState.keepProcessAlive(state) && !IndexerState.isHoldingRealtime(state)) {
46
+ return await ExitOnCaughtUp.run(state);
52
47
  } else {
53
48
  return;
54
49
  }
@@ -70,7 +65,8 @@ async function processNextBatch(state, scheduleFetch) {
70
65
  }
71
66
  IndexerState.clearRollback(state);
72
67
  IndexerState.applyBatchProgress(state, batch);
73
- if (IndexerState.isFinalizingIndexes(state)) {
68
+ IndexerState.reportFinished(state);
69
+ if (IndexerState.shouldFinalizeIndexes(state)) {
74
70
  await FinalizeBackfill.run(state);
75
71
  }
76
72
  if (!isRealtimeBeforeUpdate && IndexerState.isRealtime(state)) {
@@ -78,10 +74,7 @@ async function processNextBatch(state, scheduleFetch) {
78
74
  scheduleFetch();
79
75
  }
80
76
  let allCaughtUp = EventProcessing.allChainsEventsProcessedToEndblock(IndexerState.chainStates(state));
81
- if (allCaughtUp) {
82
- Logging.info("All chains are caught up to end blocks.");
83
- }
84
- if (allCaughtUp && !IndexerState.keepProcessAlive(state)) {
77
+ if (allCaughtUp && !IndexerState.keepProcessAlive(state) && !IndexerState.isHoldingRealtime(state)) {
85
78
  return await ExitOnCaughtUp.run(state);
86
79
  } else if (!allCaughtUp && IndexerState.exitAfterFirstEventBlock(state) && Object.values(IndexerState.chainStates(state)).every(ChainState.isAtHeadWithoutEndBlock)) {
87
80
  return IndexerState.errorExit(state, ErrorHandling.make(new Error("No events found between startBlock and chain head. Cannot auto-detect endBlock."), undefined, undefined));
package/src/Bin.res CHANGED
@@ -51,23 +51,30 @@ let applyEnv = (env: dict<JSON.t>) =>
51
51
 
52
52
  let run = async args => {
53
53
  try {
54
- switch (await Core.runCli(args))->Null.toOption {
55
- // Rust-only command (codegen / init / stop / docker / metrics / help /
56
- // version / scripts) — nothing for JS to do, exit cleanly.
57
- | None => ()
58
- | Some(json) =>
59
- switch decodeCommand(json->JSON.parseOrThrow) {
60
- | Start({reset, cwd, env, config}) =>
61
- Config.prime(config)
62
- processChdir(cwd)
63
- applyEnv(env)
64
- await Main.start(~reset)
65
- | Migrate({reset, config}) =>
66
- Config.prime(config)
67
- await Main.migrate(~reset)
68
- | DropSchema({config}) =>
69
- Config.prime(config)
70
- await Main.dropSchema()
54
+ if Worker.isEnabled {
55
+ Worker.bindToSupervisor()
56
+ // Its working directory, its environment and the chains it drives all came
57
+ // with the fork, so a worker starts the same way every other process does.
58
+ await Main.start()
59
+ } else {
60
+ switch (await Core.runCli(args))->Null.toOption {
61
+ // Rust-only command (codegen / init / stop / docker / metrics / help /
62
+ // version / scripts) — nothing for JS to do, exit cleanly.
63
+ | None => ()
64
+ | Some(json) =>
65
+ switch decodeCommand(json->JSON.parseOrThrow) {
66
+ | Start({reset, cwd, env, config}) =>
67
+ Config.prime(config)
68
+ processChdir(cwd)
69
+ applyEnv(env)
70
+ await Main.start(~reset)
71
+ | Migrate({reset, config}) =>
72
+ Config.prime(config)
73
+ await Main.migrate(~reset)
74
+ | DropSchema({config}) =>
75
+ Config.prime(config)
76
+ await Main.dropSchema()
77
+ }
71
78
  }
72
79
  }
73
80
  } catch {
package/src/Bin.res.mjs CHANGED
@@ -4,6 +4,7 @@ import * as Core from "./Core.res.mjs";
4
4
  import * as Main from "./Main.res.mjs";
5
5
  import * as Utils from "./Utils.res.mjs";
6
6
  import * as Config from "./Config.res.mjs";
7
+ import * as Worker from "./Worker.res.mjs";
7
8
  import * as Logging from "./Logging.res.mjs";
8
9
  import * as Process from "process";
9
10
  import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
@@ -57,6 +58,10 @@ function applyEnv(env) {
57
58
 
58
59
  async function run(args) {
59
60
  try {
61
+ if (Worker.isEnabled) {
62
+ Worker.bindToSupervisor();
63
+ return await Main.start(undefined, undefined, undefined, undefined, undefined);
64
+ }
60
65
  let json = await Core.runCli(args);
61
66
  if (json === null) {
62
67
  return;
@@ -12,16 +12,16 @@ let runContractRegistersOrThrow = async (
12
12
  ~itemsWithContractRegister: array<Internal.item>,
13
13
  ~config: Config.t,
14
14
  ~chainState: ChainState.t,
15
- ~transactionStore: option<TransactionStore.t>,
16
15
  ) => {
17
16
  // contractRegister handlers can read event.transaction and event.block, so
18
17
  // materialise the selected fields onto the payloads before running them. All
19
- // items belong to the chain being fetched: transactions come from its
20
- // response page, blocks from the chain store the page was merged into.
18
+ // items belong to the chain being fetched, and both stores are the chain's
19
+ // own, which this response's pages have already been merged into.
21
20
  await ChainState.materializePageItems(
22
21
  ~items=itemsWithContractRegister,
23
- ~transactionStore,
22
+ ~transactionStore=chainState->ChainState.transactionStore,
24
23
  ~blockStore=chainState->ChainState.blockStore,
24
+ ~shouldChecksum=chainState->ChainState.shouldChecksum,
25
25
  )
26
26
 
27
27
  let registrations: array<AddressStore.registration> = []
@@ -113,14 +113,13 @@ let rec onQueryResponse = async (
113
113
  latestFetchedBlockNumber,
114
114
  stats,
115
115
  knownHeight,
116
- fromBlockQueried,
117
116
  } = response
118
117
 
119
118
  chainState->ChainState.recordBlockRangeFetch(
120
119
  ~totalTimeElapsed=stats.totalTimeElapsed,
121
120
  ~parsingTimeElapsed=stats.parsingTimeElapsed->Option.getOr(0.),
122
121
  ~numEvents=parsedQueueItems->Array.length,
123
- ~blockRangeSize=latestFetchedBlockNumber - fromBlockQueried + 1,
122
+ ~blockRangeSize=latestFetchedBlockNumber - query.fromBlock + 1,
124
123
  )
125
124
 
126
125
  let numContractRegisterEvents = parsedQueueItems->Array.reduce(0, (count, item) => {
@@ -132,7 +131,7 @@ let rec onQueryResponse = async (
132
131
  "msg": "Finished querying",
133
132
  "chainId": chainId,
134
133
  "partitionId": query.partitionId,
135
- "fromBlock": fromBlockQueried,
134
+ "fromBlock": query.fromBlock,
136
135
  "toBlock": latestFetchedBlockNumber,
137
136
  "numEvents": parsedQueueItems->Array.length,
138
137
  })
@@ -141,7 +140,7 @@ let rec onQueryResponse = async (
141
140
  "msg": "Finished querying",
142
141
  "chainId": chainId,
143
142
  "partitionId": query.partitionId,
144
- "fromBlock": fromBlockQueried,
143
+ "fromBlock": query.fromBlock,
145
144
  "toBlock": latestFetchedBlockNumber,
146
145
  "numEvents": parsedQueueItems->Array.length,
147
146
  "numContractRegisterEvents": numContractRegisterEvents,
@@ -200,7 +199,18 @@ let rec onQueryResponse = async (
200
199
  // Advances synchronously to FindingReorgDepth, so a concurrent rollback
201
200
  // kick (eg from the processing loop quiescing) collapses into this one.
202
201
  scheduleRollback()
202
+ // No rollback: either the guard found no reorg, or it found one and this
203
+ // chain only reports them. Either way the guard has merged the blocks, so
204
+ // the transactions follow. A source that reads the chain store to decide
205
+ // what to fetch leaves out what the store already holds, so its page alone
206
+ // does not cover its own items — only the merged store does, and contract
207
+ // registers read it below.
203
208
  | None =>
209
+ switch transactionStore {
210
+ | Some(page) => chainState->ChainState.transactionStore->TransactionStore.merge(page)
211
+ | None => ()
212
+ }
213
+
204
214
  // Over-fetched events (a merged partition returning an address before its
205
215
  // effectiveStartBlock, a wildcard param referencing an address registered
206
216
  // after the log's block, or a registration whose own start block is later
@@ -228,7 +238,6 @@ let rec onQueryResponse = async (
228
238
  ~knownHeight,
229
239
  ~latestFetchedBlock=latestFetchedBlockNumber,
230
240
  ~query,
231
- ~transactionStore,
232
241
  )
233
242
  ChainMetadata.stage(state)
234
243
  scheduleFetch()
@@ -242,7 +251,6 @@ let rec onQueryResponse = async (
242
251
  ~itemsWithContractRegister,
243
252
  ~config=state->IndexerState.config,
244
253
  ~chainState,
245
- ~transactionStore,
246
254
  ) {
247
255
  | exception exn => IndexerState.errorExit(state, exn->ErrorHandling.make)
248
256
  | newRegistrations => proceed(~newRegistrations)
@@ -259,10 +267,8 @@ and applyQueryResponse = (
259
267
  ~knownHeight,
260
268
  ~latestFetchedBlock,
261
269
  ~query,
262
- ~transactionStore,
263
270
  ) => {
264
271
  let chainState = state->IndexerState.getChainState(~chainId)
265
- let wasFetchingAtHead = chainState->ChainState.isFetchingAtHead
266
272
 
267
273
  chainState->ChainState.handleQueryResult(
268
274
  ~query,
@@ -270,7 +276,6 @@ and applyQueryResponse = (
270
276
  ~newItems,
271
277
  ~newRegistrations,
272
278
  ~knownHeight,
273
- ~transactionStore,
274
279
  )
275
280
 
276
281
  // In auto-exit mode, set endBlock to the first event's block when events arrive.
@@ -279,17 +284,6 @@ and applyQueryResponse = (
279
284
  ~blockNumber=newItems->Array.getUnsafe(0)->Internal.getItemBlockNumber,
280
285
  )
281
286
  }
282
-
283
- // Log the backfill→head transition once: this response brought the fetch
284
- // frontier to the head. Gated on !isReady so realtime re-catch-ups (a new
285
- // block arrives, gets fetched) don't spam the log after the chain is synced.
286
- if (
287
- !wasFetchingAtHead &&
288
- !(chainState->ChainState.isReady) &&
289
- chainState->ChainState.isFetchingAtHead
290
- ) {
291
- chainState->ChainState.logger->Logging.childInfo("All events have been fetched")
292
- }
293
287
  }
294
288
 
295
289
  let finishWaitingForNewBlock = (
@@ -13,11 +13,12 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
13
13
  import * as ReorgDetection from "./ReorgDetection.res.mjs";
14
14
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
15
15
  import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
16
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
16
17
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
17
18
  import * as ContractRegisterContext from "./ContractRegisterContext.res.mjs";
18
19
 
19
- async function runContractRegistersOrThrow(itemsWithContractRegister, config, chainState, transactionStore) {
20
- await ChainState.materializePageItems(itemsWithContractRegister, transactionStore, ChainState.blockStore(chainState));
20
+ async function runContractRegistersOrThrow(itemsWithContractRegister, config, chainState) {
21
+ await ChainState.materializePageItems(itemsWithContractRegister, ChainState.transactionStore(chainState), ChainState.blockStore(chainState), ChainState.shouldChecksum(chainState));
21
22
  let registrations = [];
22
23
  let onRegister = (item, contractAddress, contractName) => {
23
24
  registrations.push({
@@ -63,15 +64,11 @@ async function runContractRegistersOrThrow(itemsWithContractRegister, config, ch
63
64
  return registrations;
64
65
  }
65
66
 
66
- function applyQueryResponse(state, chainId, newItems, newRegistrations, knownHeight, latestFetchedBlock, query, transactionStore) {
67
+ function applyQueryResponse(state, chainId, newItems, newRegistrations, knownHeight, latestFetchedBlock, query) {
67
68
  let chainState = IndexerState.getChainState(state, chainId);
68
- let wasFetchingAtHead = ChainState.isFetchingAtHead(chainState);
69
- ChainState.handleQueryResult(chainState, query, newItems, newRegistrations, latestFetchedBlock, knownHeight, transactionStore);
69
+ ChainState.handleQueryResult(chainState, query, newItems, newRegistrations, latestFetchedBlock, knownHeight);
70
70
  if (IndexerState.exitAfterFirstEventBlock(state) && newItems.length !== 0) {
71
- ChainState.setEndBlockToFirstEvent(chainState, newItems[0].blockNumber);
72
- }
73
- if (!wasFetchingAtHead && !ChainState.isReady(chainState) && ChainState.isFetchingAtHead(chainState)) {
74
- return Logging.childInfo(ChainState.logger(chainState), "All events have been fetched");
71
+ return ChainState.setEndBlockToFirstEvent(chainState, newItems[0].blockNumber);
75
72
  }
76
73
  }
77
74
 
@@ -85,11 +82,10 @@ async function onQueryResponse(state, param, stateId, scheduleFetch, schedulePro
85
82
  let chainState = IndexerState.getChainState(state, chainId);
86
83
  let stats = response.stats;
87
84
  let latestFetchedBlockNumber = response.latestFetchedBlockNumber;
88
- let fromBlockQueried = response.fromBlockQueried;
89
85
  let transactionStore = response.transactionStore;
90
86
  let parsedQueueItems = response.parsedQueueItems;
91
87
  let knownHeight = response.knownHeight;
92
- ChainState.recordBlockRangeFetch(chainState, stats["total time elapsed (s)"], Stdlib_Option.getOr(stats["parsing time (s)"], 0), parsedQueueItems.length, (latestFetchedBlockNumber - fromBlockQueried | 0) + 1 | 0);
88
+ ChainState.recordBlockRangeFetch(chainState, stats["total time elapsed (s)"], Stdlib_Option.getOr(stats["parsing time (s)"], 0), parsedQueueItems.length, (latestFetchedBlockNumber - query.fromBlock | 0) + 1 | 0);
93
89
  let numContractRegisterEvents = Stdlib_Array.reduce(parsedQueueItems, 0, (count, item) => {
94
90
  if (item.onEventRegistration.contractRegister !== undefined) {
95
91
  return count + 1 | 0;
@@ -102,7 +98,7 @@ async function onQueryResponse(state, param, stateId, scheduleFetch, schedulePro
102
98
  msg: "Finished querying",
103
99
  chainId: chainId,
104
100
  partitionId: query.partitionId,
105
- fromBlock: fromBlockQueried,
101
+ fromBlock: query.fromBlock,
106
102
  toBlock: latestFetchedBlockNumber,
107
103
  numEvents: parsedQueueItems.length
108
104
  });
@@ -111,7 +107,7 @@ async function onQueryResponse(state, param, stateId, scheduleFetch, schedulePro
111
107
  msg: "Finished querying",
112
108
  chainId: chainId,
113
109
  partitionId: query.partitionId,
114
- fromBlock: fromBlockQueried,
110
+ fromBlock: query.fromBlock,
115
111
  toBlock: latestFetchedBlockNumber,
116
112
  numEvents: parsedQueueItems.length,
117
113
  numContractRegisterEvents: numContractRegisterEvents
@@ -135,6 +131,9 @@ async function onQueryResponse(state, param, stateId, scheduleFetch, schedulePro
135
131
  IndexerState.beginReorg(state, chainId, rollbackWithReorgDetectedBlockNumber);
136
132
  return scheduleRollback();
137
133
  }
134
+ if (transactionStore !== undefined) {
135
+ ChainState.transactionStore(chainState).merge(Primitive_option.valFromOption(transactionStore));
136
+ }
138
137
  let itemsWithContractRegister = [];
139
138
  for (let idx = 0, idx_finish = parsedQueueItems.length; idx < idx_finish; ++idx) {
140
139
  let item = parsedQueueItems[idx];
@@ -144,7 +143,7 @@ async function onQueryResponse(state, param, stateId, scheduleFetch, schedulePro
144
143
  }
145
144
  let proceed = newRegistrations => {
146
145
  if (!IndexerState.isStale(state, stateId)) {
147
- applyQueryResponse(state, chainId, parsedQueueItems, newRegistrations, knownHeight, latestFetchedBlockNumber, query, transactionStore);
146
+ applyQueryResponse(state, chainId, parsedQueueItems, newRegistrations, knownHeight, latestFetchedBlockNumber, query);
148
147
  ChainMetadata.stage(state);
149
148
  scheduleFetch();
150
149
  return scheduleProcessing();
@@ -155,7 +154,7 @@ async function onQueryResponse(state, param, stateId, scheduleFetch, schedulePro
155
154
  }
156
155
  let newRegistrations;
157
156
  try {
158
- newRegistrations = await runContractRegistersOrThrow(itemsWithContractRegister, IndexerState.config(state), chainState, transactionStore);
157
+ newRegistrations = await runContractRegistersOrThrow(itemsWithContractRegister, IndexerState.config(state), chainState);
159
158
  } catch (raw_exn) {
160
159
  let exn = Primitive_exceptions.internalToException(raw_exn);
161
160
  return IndexerState.errorExit(state, ErrorHandling.make(exn, undefined, undefined));