envio 2.29.0-alpha.2 → 2.29.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.
@@ -51,7 +51,6 @@ type t = {
51
51
  // Used for the incremental partition id. Can't use the partitions length,
52
52
  // since partitions might be deleted on merge or cleaned up
53
53
  nextPartitionIndex: int,
54
- isFetchingAtHead: bool,
55
54
  startBlock: int,
56
55
  endBlock: option<int>,
57
56
  maxAddrInPartition: int,
@@ -65,14 +64,23 @@ type t = {
65
64
  dcsToStore: option<array<indexingContract>>,
66
65
  // Not used for logic - only metadata
67
66
  chainId: int,
68
- // Fields computed by updateInternal
67
+ // The block number of the latest block fetched
68
+ // which added all its events to the queue
69
69
  latestFullyFetchedBlock: blockNumberAndTimestamp,
70
+ // The block number of the latest block which was added to the queue
71
+ // by the onBlock configs
72
+ // Need a separate pointer for this
73
+ // to prevent OOM when adding too many items to the queue
74
+ latestOnBlockBlockNumber: int,
70
75
  // How much blocks behind the head we should query
71
76
  // Needed to query before entering reorg threshold
72
77
  blockLag: int,
73
78
  //Items ordered from latest to earliest
74
79
  queue: array<Internal.item>,
75
- onBlockConfigs: option<array<Internal.onBlockConfig>>,
80
+ // How many items we should aim to have in the buffer
81
+ // ready for processing
82
+ targetBufferSize: int,
83
+ onBlockConfigs: array<Internal.onBlockConfig>,
76
84
  }
77
85
 
78
86
  let copy = (fetchState: t) => {
@@ -82,8 +90,8 @@ let copy = (fetchState: t) => {
82
90
  startBlock: fetchState.startBlock,
83
91
  endBlock: fetchState.endBlock,
84
92
  nextPartitionIndex: fetchState.nextPartitionIndex,
85
- isFetchingAtHead: fetchState.isFetchingAtHead,
86
93
  latestFullyFetchedBlock: fetchState.latestFullyFetchedBlock,
94
+ latestOnBlockBlockNumber: fetchState.latestOnBlockBlockNumber,
87
95
  normalSelection: fetchState.normalSelection,
88
96
  chainId: fetchState.chainId,
89
97
  contractConfigs: fetchState.contractConfigs,
@@ -92,6 +100,7 @@ let copy = (fetchState: t) => {
92
100
  blockLag: fetchState.blockLag,
93
101
  queue: fetchState.queue->Array.copy,
94
102
  onBlockConfigs: fetchState.onBlockConfigs,
103
+ targetBufferSize: fetchState.targetBufferSize,
95
104
  }
96
105
  }
97
106
 
@@ -173,33 +182,40 @@ let mergeIntoPartition = (p: partition, ~target: partition, ~maxAddrInPartition)
173
182
  }
174
183
  }
175
184
 
176
- /* strategy for TUI synced status:
177
- * Firstly -> only update synced status after batch is processed (not on batch creation). But also set when a batch tries to be created and there is no batch
178
- *
179
- * Secondly -> reset timestampCaughtUpToHead and isFetching at head when dynamic contracts get registered to a chain if they are not within 0.001 percent of the current block height
180
- *
181
- * New conditions for valid synced:
182
- *
183
- * CASE 1 (chains are being synchronised at the head)
184
- *
185
- * All chain fetchers are fetching at the head AND
186
- * No events that can be processed on the queue (even if events still exist on the individual queues)
187
- * CASE 2 (chain finishes earlier than any other chain)
188
- *
189
- * CASE 3 endblock has been reached and latest processed block is greater than or equal to endblock (both fields must be Some)
190
- *
191
- * The given chain fetcher is fetching at the head or latest processed block >= endblock
192
- * The given chain has processed all events on the queue
193
- * see https://github.com/Float-Capital/indexer/pull/1388 */
194
-
195
- /* Dynamic contracts pose a unique case when calculated whether a chain is synced or not.
196
- * Specifically, in the initial syncing state from SearchingForEvents -> Synced, where although a chain has technically processed up to all blocks
197
- * for a contract that emits events with dynamic contracts, it is possible that those dynamic contracts will need to be indexed from blocks way before
198
- * the current block height. This is a toleration check where if there are dynamic contracts within a batch, check how far are they from the currentblock height.
199
- * If it is less than 1 thousandth of a percent, then we deem that contract to be within the synced range, and therefore do not reset the synced status of the chain */
200
- let checkIsWithinSyncRange = (~latestFetchedBlock: blockNumberAndTimestamp, ~currentBlockHeight) =>
201
- (currentBlockHeight->Int.toFloat -. latestFetchedBlock.blockNumber->Int.toFloat) /.
202
- currentBlockHeight->Int.toFloat <= 0.001
185
+ @inline
186
+ let bufferBlockNumber = ({latestFullyFetchedBlock, latestOnBlockBlockNumber}: t) => {
187
+ latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber
188
+ ? latestOnBlockBlockNumber
189
+ : latestFullyFetchedBlock.blockNumber
190
+ }
191
+
192
+ /**
193
+ * Returns the latest block which is ready to be consumed
194
+ */
195
+ @inline
196
+ let bufferBlock = ({latestFullyFetchedBlock, latestOnBlockBlockNumber}: t) => {
197
+ latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber
198
+ ? {
199
+ blockNumber: latestOnBlockBlockNumber,
200
+ blockTimestamp: 0,
201
+ }
202
+ : latestFullyFetchedBlock
203
+ }
204
+
205
+ /*
206
+ Comparitor for two events from the same chain. No need for chain id or timestamp
207
+ */
208
+ let compareBufferItem = (a: Internal.item, b: Internal.item) => {
209
+ let blockDiff = b->Internal.getItemBlockNumber - a->Internal.getItemBlockNumber
210
+ if blockDiff === 0 {
211
+ b->Internal.getItemLogIndex - a->Internal.getItemLogIndex
212
+ } else {
213
+ blockDiff
214
+ }
215
+ }
216
+
217
+ // Some big number which should be bigger than any log index
218
+ let blockItemLogIndex = 16777216
203
219
 
204
220
  /*
205
221
  Update fetchState, merge registers and recompute derived values
@@ -210,8 +226,7 @@ let updateInternal = (
210
226
  ~nextPartitionIndex=fetchState.nextPartitionIndex,
211
227
  ~indexingContracts=fetchState.indexingContracts,
212
228
  ~dcsToStore=fetchState.dcsToStore,
213
- ~currentBlockHeight=?,
214
- ~queue=fetchState.queue,
229
+ ~mutItems=?,
215
230
  ~blockLag=fetchState.blockLag,
216
231
  ): t => {
217
232
  let firstPartition = partitions->Js.Array2.unsafe_get(0)
@@ -224,35 +239,79 @@ let updateInternal = (
224
239
  }
225
240
  let latestFullyFetchedBlock = latestFullyFetchedBlock.contents
226
241
 
227
- let isFetchingAtHead = switch currentBlockHeight {
228
- | None => fetchState.isFetchingAtHead
229
- | Some(currentBlockHeight) =>
230
- // Sync isFetchingAtHead when currentBlockHeight is provided
231
- if latestFullyFetchedBlock.blockNumber >= currentBlockHeight {
232
- true
233
- } else if (
234
- // For dc registration reset the state only when dcs are not in the sync range
235
- fetchState.isFetchingAtHead &&
236
- checkIsWithinSyncRange(~latestFetchedBlock=latestFullyFetchedBlock, ~currentBlockHeight)
237
- ) {
238
- true
239
- } else {
240
- false
242
+ let mutItemsRef = ref(mutItems)
243
+
244
+ let latestOnBlockBlockNumber = switch fetchState.onBlockConfigs {
245
+ | [] => latestFullyFetchedBlock.blockNumber
246
+ | onBlockConfigs => {
247
+ // Calculate the max block number we are going to create items for
248
+ // Use -targetBufferSize to get the last target item in the queue (which is reversed)
249
+ //
250
+ // mutItems is not very reliable, since it might not be sorted,
251
+ // but the chances for it happen are very low and not critical
252
+ //
253
+ // All this needed to prevent OOM when adding too many block items to the queue
254
+ let maxBlockNumber = switch switch mutItemsRef.contents {
255
+ | Some(mutItems) => mutItems
256
+ | None => fetchState.queue
257
+ }->Utils.Array.at(-fetchState.targetBufferSize) {
258
+ | Some(item) => item->Internal.getItemBlockNumber
259
+ | None => latestFullyFetchedBlock.blockNumber
260
+ }
261
+
262
+ let mutItems = switch mutItemsRef.contents {
263
+ | Some(mutItems) => mutItems
264
+ | None => fetchState.queue->Array.copy
265
+ }
266
+ mutItemsRef := Some(mutItems)
267
+
268
+ let newItemsCounter = ref(0)
269
+ let latestOnBlockBlockNumber = ref(fetchState.latestOnBlockBlockNumber)
270
+
271
+ // Simply iterate over every block
272
+ // could have a better algorithm to iterate over blocks in a more efficient way
273
+ // but raw loops are fast enough
274
+ while (
275
+ latestOnBlockBlockNumber.contents < maxBlockNumber &&
276
+ // Additional safeguard to prevent OOM
277
+ newItemsCounter.contents <= fetchState.targetBufferSize
278
+ ) {
279
+ let blockNumber = latestOnBlockBlockNumber.contents + 1
280
+ latestOnBlockBlockNumber := blockNumber
281
+
282
+ for configIdx in 0 to onBlockConfigs->Array.length - 1 {
283
+ let onBlockConfig = onBlockConfigs->Js.Array2.unsafe_get(configIdx)
284
+
285
+ let handlerStartBlock = switch onBlockConfig.startBlock {
286
+ | Some(startBlock) => startBlock
287
+ | None => fetchState.startBlock
288
+ }
289
+
290
+ if (
291
+ blockNumber >= handlerStartBlock &&
292
+ switch onBlockConfig.endBlock {
293
+ | Some(endBlock) => blockNumber <= endBlock
294
+ | None => true
295
+ } &&
296
+ (blockNumber - handlerStartBlock)->Pervasives.mod(onBlockConfig.interval) === 0
297
+ ) {
298
+ mutItems->Array.push(
299
+ Block({
300
+ onBlockConfig,
301
+ blockNumber,
302
+ logIndex: blockItemLogIndex + onBlockConfig.index,
303
+ }),
304
+ )
305
+ newItemsCounter := newItemsCounter.contents + 1
306
+ }
307
+ }
308
+ }
309
+
310
+ latestOnBlockBlockNumber.contents
241
311
  }
242
312
  }
243
313
 
244
- let bufferSize = queue->Array.length
245
- Prometheus.IndexingPartitions.set(
246
- ~partitionsCount=partitions->Array.length,
247
- ~chainId=fetchState.chainId,
248
- )
249
- Prometheus.IndexingBufferSize.set(~bufferSize, ~chainId=fetchState.chainId)
250
- Prometheus.IndexingBufferBlockNumber.set(
251
- ~blockNumber=latestFullyFetchedBlock.blockNumber,
252
- ~chainId=fetchState.chainId,
253
- )
254
-
255
- {
314
+ let updatedFetchState = {
256
315
  maxAddrInPartition: fetchState.maxAddrInPartition,
257
316
  startBlock: fetchState.startBlock,
258
317
  endBlock: fetchState.endBlock,
@@ -260,15 +319,37 @@ let updateInternal = (
260
319
  normalSelection: fetchState.normalSelection,
261
320
  chainId: fetchState.chainId,
262
321
  onBlockConfigs: fetchState.onBlockConfigs,
322
+ targetBufferSize: fetchState.targetBufferSize,
263
323
  nextPartitionIndex,
264
324
  partitions,
265
- isFetchingAtHead,
325
+ latestOnBlockBlockNumber,
266
326
  latestFullyFetchedBlock,
267
327
  indexingContracts,
268
328
  dcsToStore,
269
329
  blockLag,
270
- queue,
330
+ queue: switch mutItemsRef.contents {
331
+ // Theoretically it could be faster to asume that
332
+ // the items are sorted, but there are cases
333
+ // when the data source returns them unsorted
334
+ | Some(mutItems) => mutItems->Js.Array2.sortInPlaceWith(compareBufferItem)
335
+ | None => fetchState.queue
336
+ },
271
337
  }
338
+
339
+ Prometheus.IndexingPartitions.set(
340
+ ~partitionsCount=partitions->Array.length,
341
+ ~chainId=fetchState.chainId,
342
+ )
343
+ Prometheus.IndexingBufferSize.set(
344
+ ~bufferSize=updatedFetchState.queue->Array.length,
345
+ ~chainId=fetchState.chainId,
346
+ )
347
+ Prometheus.IndexingBufferBlockNumber.set(
348
+ ~blockNumber=updatedFetchState->bufferBlockNumber,
349
+ ~chainId=fetchState.chainId,
350
+ )
351
+
352
+ updatedFetchState
272
353
  }
273
354
 
274
355
  let numAddresses = fetchState => fetchState.indexingContracts->Js.Dict.keys->Array.length
@@ -290,7 +371,6 @@ let registerDynamicContracts = (
290
371
  // These are raw dynamic contracts received from contractRegister call.
291
372
  // Might contain duplicates which we should filter out
292
373
  dynamicContracts: array<indexingContract>,
293
- ~currentBlockHeight,
294
374
  ) => {
295
375
  if fetchState.normalSelection.eventConfigs->Utils.Array.isEmpty {
296
376
  // Can the normalSelection be empty?
@@ -509,7 +589,6 @@ let registerDynamicContracts = (
509
589
 
510
590
  fetchState->updateInternal(
511
591
  ~partitions=fetchState.partitions->Js.Array2.concat(newPartitions),
512
- ~currentBlockHeight,
513
592
  ~dcsToStore=switch fetchState.dcsToStore {
514
593
  | Some(existingDcs) => Some(Array.concat(existingDcs, dcsToStore))
515
594
  | None => Some(dcsToStore)
@@ -546,21 +625,6 @@ type query = {
546
625
  exception UnexpectedPartitionNotFound({partitionId: string})
547
626
  exception UnexpectedMergeQueryResponse({message: string})
548
627
 
549
- /*
550
- Comparitor for two events from the same chain. No need for chain id or timestamp
551
- */
552
- let compareBufferItem = (a: Internal.item, b: Internal.item) => {
553
- let blockDiff = b->Internal.getItemBlockNumber - a->Internal.getItemBlockNumber
554
- if blockDiff === 0 {
555
- b->Internal.getItemLogIndex - a->Internal.getItemLogIndex
556
- } else {
557
- blockDiff
558
- }
559
- }
560
-
561
- // Some big number which should be bigger than any log index
562
- let blockItemLogIndex = 16777216
563
-
564
628
  /*
565
629
  Updates fetchState with a response for a given query.
566
630
  Returns Error if the partition with given query cannot be found (unexpected)
@@ -573,7 +637,6 @@ let handleQueryResult = (
573
637
  ~query: query,
574
638
  ~latestFetchedBlock: blockNumberAndTimestamp,
575
639
  ~newItems,
576
- ~currentBlockHeight,
577
640
  ): result<t, exn> =>
578
641
  {
579
642
  let partitionId = query.partitionId
@@ -626,59 +689,14 @@ let handleQueryResult = (
626
689
  )
627
690
  }
628
691
  }->Result.map(partitions => {
629
- let newQueue = fetchState.queue->Array.concat(newItems)
630
-
631
- switch fetchState.onBlockConfigs {
632
- | Some(onBlockConfigs) => {
633
- let prevLatestFetchedBlockNumber = fetchState.latestFullyFetchedBlock.blockNumber
634
- let nextLatestFullyFetchedBlockNumber = {
635
- let nextLatestFullyFetchedBlockNumber = ref(latestFetchedBlock.blockNumber)
636
- for idx in 0 to partitions->Array.length - 1 {
637
- let p = partitions->Js.Array2.unsafe_get(idx)
638
- if nextLatestFullyFetchedBlockNumber.contents > p.latestFetchedBlock.blockNumber {
639
- nextLatestFullyFetchedBlockNumber := p.latestFetchedBlock.blockNumber
640
- }
641
- }
642
- nextLatestFullyFetchedBlockNumber.contents
643
- }
644
-
645
- if nextLatestFullyFetchedBlockNumber > prevLatestFetchedBlockNumber {
646
- for configIdx in 0 to onBlockConfigs->Array.length - 1 {
647
- let onBlockConfig = onBlockConfigs->Js.Array2.unsafe_get(configIdx)
648
-
649
- let handlerStartBlock = switch onBlockConfig.startBlock {
650
- | Some(startBlock) => startBlock
651
- | None => fetchState.startBlock
652
- }
653
- let rangeStart = Pervasives.max(handlerStartBlock, prevLatestFetchedBlockNumber + 1)
654
- let rangeEnd = switch onBlockConfig.endBlock {
655
- | Some(endBlock) => Pervasives.min(endBlock, nextLatestFullyFetchedBlockNumber)
656
- | None => nextLatestFullyFetchedBlockNumber
657
- }
658
- if rangeStart <= rangeEnd {
659
- for blockNumber in rangeStart to rangeEnd {
660
- if (blockNumber - handlerStartBlock)->Pervasives.mod(onBlockConfig.interval) === 0 {
661
- newQueue->Array.push(
662
- Block({onBlockConfig, blockNumber, logIndex: blockItemLogIndex}),
663
- )
664
- }
665
- }
666
- }
667
- }
668
- }
669
- }
670
-
671
- | None => ()
672
- }
673
-
674
692
  fetchState->updateInternal(
675
693
  ~partitions,
676
- ~currentBlockHeight,
677
- ~queue=newQueue
678
- // Theoretically it could be faster to asume that
679
- // the items are sorted, but there are cases
680
- // when the data source returns them unsorted
681
- ->Js.Array2.sortInPlaceWith(compareBufferItem),
694
+ ~mutItems=?{
695
+ switch newItems {
696
+ | [] => None
697
+ | _ => Some(fetchState.queue->Array.concat(newItems))
698
+ }
699
+ },
682
700
  )
683
701
  })
684
702
 
@@ -757,9 +775,16 @@ let isFullPartition = (p: partition, ~maxAddrInPartition) => {
757
775
  }
758
776
 
759
777
  let getNextQuery = (
760
- {queue, partitions, maxAddrInPartition, endBlock, indexingContracts, blockLag}: t,
778
+ {
779
+ queue,
780
+ partitions,
781
+ targetBufferSize,
782
+ maxAddrInPartition,
783
+ endBlock,
784
+ indexingContracts,
785
+ blockLag,
786
+ }: t,
761
787
  ~concurrencyLimit,
762
- ~targetBufferSize,
763
788
  ~currentBlockHeight,
764
789
  ~stateId,
765
790
  ) => {
@@ -951,19 +976,20 @@ Gets the earliest queueItem from thgetNodeEarliestEventWithUpdatedQueue.
951
976
  Finds the earliest queue item across all partitions and then returns that
952
977
  queue item with an update fetch state.
953
978
  */
954
- let getEarliestEvent = ({queue, latestFullyFetchedBlock}: t) => {
955
- switch queue->Utils.Array.last {
979
+ let getEarliestEvent = (fetchState: t) => {
980
+ let {queue} = fetchState
981
+ switch fetchState.queue->Utils.Array.last {
956
982
  | Some(item) =>
957
- if item->Internal.getItemBlockNumber <= latestFullyFetchedBlock.blockNumber {
983
+ if item->Internal.getItemBlockNumber <= fetchState->bufferBlockNumber {
958
984
  Item({item, popItemOffQueue: () => queue->Js.Array2.pop->ignore})
959
985
  } else {
960
986
  NoItem({
961
- latestFetchedBlock: latestFullyFetchedBlock,
987
+ latestFetchedBlock: fetchState->bufferBlock,
962
988
  })
963
989
  }
964
990
  | None =>
965
991
  NoItem({
966
- latestFetchedBlock: latestFullyFetchedBlock,
992
+ latestFetchedBlock: fetchState->bufferBlock,
967
993
  })
968
994
  }
969
995
  }
@@ -978,8 +1004,9 @@ let make = (
978
1004
  ~contracts: array<indexingContract>,
979
1005
  ~maxAddrInPartition,
980
1006
  ~chainId,
1007
+ ~targetBufferSize,
981
1008
  ~progressBlockNumber=startBlock - 1,
982
- ~onBlockConfigs=?,
1009
+ ~onBlockConfigs=[],
983
1010
  ~blockLag=0,
984
1011
  ): t => {
985
1012
  let latestFetchedBlock = {
@@ -1095,28 +1122,24 @@ let make = (
1095
1122
  partitions,
1096
1123
  nextPartitionIndex: partitions->Array.length,
1097
1124
  contractConfigs,
1098
- isFetchingAtHead: false,
1099
1125
  maxAddrInPartition,
1100
1126
  chainId,
1101
1127
  startBlock,
1102
1128
  endBlock,
1103
1129
  latestFullyFetchedBlock: latestFetchedBlock,
1130
+ latestOnBlockBlockNumber: progressBlockNumber,
1104
1131
  normalSelection,
1105
1132
  indexingContracts,
1106
1133
  dcsToStore: None,
1107
1134
  blockLag,
1108
1135
  onBlockConfigs,
1136
+ targetBufferSize,
1109
1137
  queue: [],
1110
1138
  }
1111
1139
  }
1112
1140
 
1113
1141
  let bufferSize = ({queue}: t) => queue->Array.length
1114
1142
 
1115
- /**
1116
- * Returns the latest block number fetched for the lowest fetcher queue (ie the earliest un-fetched dynamic contract)
1117
- */
1118
- let getLatestFullyFetchedBlock = ({latestFullyFetchedBlock}: t) => latestFullyFetchedBlock
1119
-
1120
1143
  let pruneQueueFromFirstChangeEvent = (
1121
1144
  queue: array<Internal.item>,
1122
1145
  ~firstChangeEvent: blockNumberAndLogIndex,
@@ -1142,6 +1165,7 @@ let rollbackPartition = (
1142
1165
  | {selection: {dependsOnAddresses: false}} =>
1143
1166
  Some({
1144
1167
  ...p,
1168
+ // FIXME: Should rollback latestFetchedBlock???
1145
1169
  status: {
1146
1170
  fetchingStateId: None,
1147
1171
  },
@@ -1209,10 +1233,13 @@ let rollback = (fetchState: t, ~firstChangeEvent) => {
1209
1233
  p->rollbackPartition(~firstChangeEvent, ~addressesToRemove)
1210
1234
  )
1211
1235
 
1212
- fetchState->updateInternal(
1236
+ {
1237
+ ...fetchState,
1238
+ latestOnBlockBlockNumber: firstChangeEvent.blockNumber - 1, // TODO: This is not tested
1239
+ }->updateInternal(
1213
1240
  ~partitions,
1214
1241
  ~indexingContracts,
1215
- ~queue=fetchState.queue->pruneQueueFromFirstChangeEvent(~firstChangeEvent),
1242
+ ~mutItems=fetchState.queue->pruneQueueFromFirstChangeEvent(~firstChangeEvent),
1216
1243
  ~dcsToStore=switch fetchState.dcsToStore {
1217
1244
  | Some(dcsToStore) =>
1218
1245
  let filtered =
@@ -1230,10 +1257,10 @@ let rollback = (fetchState: t, ~firstChangeEvent) => {
1230
1257
  * Returns a boolean indicating whether the fetch state is actively indexing
1231
1258
  * used for comparing event queues in the chain manager
1232
1259
  */
1233
- let isActivelyIndexing = ({latestFullyFetchedBlock, endBlock} as fetchState: t) => {
1260
+ let isActivelyIndexing = ({endBlock} as fetchState: t) => {
1234
1261
  switch endBlock {
1235
1262
  | Some(endBlock) =>
1236
- let isPastEndblock = latestFullyFetchedBlock.blockNumber >= endBlock
1263
+ let isPastEndblock = fetchState->bufferBlockNumber >= endBlock
1237
1264
  if isPastEndblock {
1238
1265
  fetchState->bufferSize > 0
1239
1266
  } else {
@@ -1244,26 +1271,27 @@ let isActivelyIndexing = ({latestFullyFetchedBlock, endBlock} as fetchState: t)
1244
1271
  }
1245
1272
 
1246
1273
  let isReadyToEnterReorgThreshold = (
1247
- {latestFullyFetchedBlock, endBlock, blockLag, queue}: t,
1274
+ {endBlock, blockLag, queue} as fetchState: t,
1248
1275
  ~currentBlockHeight,
1249
1276
  ) => {
1277
+ let bufferBlockNumber = fetchState->bufferBlockNumber
1250
1278
  currentBlockHeight !== 0 &&
1251
1279
  switch endBlock {
1252
- | Some(endBlock) if latestFullyFetchedBlock.blockNumber >= endBlock => true
1253
- | _ => latestFullyFetchedBlock.blockNumber >= currentBlockHeight - blockLag
1280
+ | Some(endBlock) if bufferBlockNumber >= endBlock => true
1281
+ | _ => bufferBlockNumber >= currentBlockHeight - blockLag
1254
1282
  } &&
1255
1283
  queue->Utils.Array.isEmpty
1256
1284
  }
1257
1285
 
1258
1286
  let filterAndSortForUnorderedBatch = {
1259
- let hasBatchItem = ({queue, latestFullyFetchedBlock}: t) => {
1287
+ let hasBatchItem = ({queue} as fetchState: t) => {
1260
1288
  switch queue->Utils.Array.last {
1261
- | Some(item) => item->Internal.getItemBlockNumber <= latestFullyFetchedBlock.blockNumber
1289
+ | Some(item) => item->Internal.getItemBlockNumber <= fetchState->bufferBlockNumber
1262
1290
  | None => false
1263
1291
  }
1264
1292
  }
1265
1293
 
1266
- let hasFullBatch = ({queue, latestFullyFetchedBlock}: t, ~maxBatchSize) => {
1294
+ let hasFullBatch = ({queue} as fetchState: t, ~maxBatchSize) => {
1267
1295
  // Queue is ordered from latest to earliest, so the earliest eligible
1268
1296
  // item for a full batch of size B is at index (length - B).
1269
1297
  // Do NOT subtract an extra 1 here; when length === B we should still
@@ -1275,7 +1303,7 @@ let filterAndSortForUnorderedBatch = {
1275
1303
  // Unsafe can fail when maxBatchSize is 0,
1276
1304
  // but we ignore the case
1277
1305
  queue->Js.Array2.unsafe_get(targetBlockIdx)->Internal.getItemBlockNumber <=
1278
- latestFullyFetchedBlock.blockNumber
1306
+ fetchState->bufferBlockNumber
1279
1307
  }
1280
1308
  }
1281
1309
 
@@ -1303,18 +1331,19 @@ let filterAndSortForUnorderedBatch = {
1303
1331
  }
1304
1332
  }
1305
1333
 
1306
- let getProgressBlockNumber = ({latestFullyFetchedBlock, queue}: t) => {
1334
+ let getProgressBlockNumber = ({queue} as fetchState: t) => {
1335
+ let bufferBlockNumber = fetchState->bufferBlockNumber
1307
1336
  switch queue->Utils.Array.last {
1308
- | Some(item) if latestFullyFetchedBlock.blockNumber >= item->Internal.getItemBlockNumber =>
1337
+ | Some(item) if bufferBlockNumber >= item->Internal.getItemBlockNumber =>
1309
1338
  item->Internal.getItemBlockNumber - 1
1310
- | _ => latestFullyFetchedBlock.blockNumber
1339
+ | _ => bufferBlockNumber
1311
1340
  }
1312
1341
  }
1313
1342
 
1314
- let getProgressNextBlockLogIndex = ({queue, latestFullyFetchedBlock}: t) => {
1343
+ let getProgressNextBlockLogIndex = ({queue} as fetchState: t) => {
1315
1344
  switch queue->Utils.Array.last {
1316
1345
  | Some(Event({logIndex, blockNumber}))
1317
- if latestFullyFetchedBlock.blockNumber >= blockNumber && logIndex > 0 =>
1346
+ if fetchState->bufferBlockNumber >= blockNumber && logIndex > 0 =>
1318
1347
  Some(logIndex - 1)
1319
1348
  | _ => None
1320
1349
  }