envio 3.2.1 → 3.3.0-alpha.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 (106) hide show
  1. package/package.json +6 -7
  2. package/src/Batch.res +12 -15
  3. package/src/Batch.res.mjs +4 -5
  4. package/src/BatchProcessing.res +199 -0
  5. package/src/BatchProcessing.res.mjs +125 -0
  6. package/src/ChainFetching.res +375 -0
  7. package/src/ChainFetching.res.mjs +206 -0
  8. package/src/ChainMetadata.res +27 -0
  9. package/src/ChainMetadata.res.mjs +27 -0
  10. package/src/ChainState.res +618 -0
  11. package/src/ChainState.res.mjs +461 -0
  12. package/src/ChainState.resi +85 -0
  13. package/src/Config.res +13 -4
  14. package/src/Config.res.mjs +8 -3
  15. package/src/ContractRegisterContext.res +106 -0
  16. package/src/ContractRegisterContext.res.mjs +76 -0
  17. package/src/Core.res +3 -0
  18. package/src/CrossChainState.res +269 -0
  19. package/src/CrossChainState.res.mjs +197 -0
  20. package/src/CrossChainState.resi +47 -0
  21. package/src/Ecosystem.res +58 -0
  22. package/src/Ecosystem.res.mjs +43 -1
  23. package/src/Env.res +7 -2
  24. package/src/Env.res.mjs +5 -2
  25. package/src/EventConfigBuilder.res +2 -2
  26. package/src/EventProcessing.res +60 -46
  27. package/src/EventProcessing.res.mjs +33 -32
  28. package/src/EventUtils.res +0 -4
  29. package/src/EventUtils.res.mjs +0 -4
  30. package/src/ExitOnCaughtUp.res +10 -0
  31. package/src/ExitOnCaughtUp.res.mjs +22 -0
  32. package/src/FetchState.res +124 -62
  33. package/src/FetchState.res.mjs +159 -93
  34. package/src/InMemoryStore.res +36 -451
  35. package/src/InMemoryStore.res.mjs +20 -369
  36. package/src/IndexerLoop.res +44 -0
  37. package/src/IndexerLoop.res.mjs +46 -0
  38. package/src/IndexerState.res +544 -0
  39. package/src/IndexerState.res.mjs +547 -0
  40. package/src/IndexerState.resi +132 -0
  41. package/src/Internal.res +29 -8
  42. package/src/LoadLayer.res +20 -18
  43. package/src/LoadLayer.res.mjs +14 -12
  44. package/src/LoadLayer.resi +6 -3
  45. package/src/Logging.res +11 -44
  46. package/src/Logging.res.mjs +10 -42
  47. package/src/Main.res +54 -79
  48. package/src/Main.res.mjs +44 -56
  49. package/src/PgStorage.res +8 -71
  50. package/src/PgStorage.res.mjs +3 -47
  51. package/src/Prometheus.res +7 -8
  52. package/src/Prometheus.res.mjs +7 -4
  53. package/src/PruneStaleHistory.res +45 -0
  54. package/src/PruneStaleHistory.res.mjs +46 -0
  55. package/src/RawEvent.res +73 -0
  56. package/src/RawEvent.res.mjs +51 -0
  57. package/src/Rollback.res +204 -0
  58. package/src/Rollback.res.mjs +118 -0
  59. package/src/SimulateItems.res +12 -10
  60. package/src/SimulateItems.res.mjs +1 -1
  61. package/src/UserContext.res +26 -114
  62. package/src/UserContext.res.mjs +15 -78
  63. package/src/Writing.res +242 -0
  64. package/src/Writing.res.mjs +215 -0
  65. package/src/db/InternalTable.res +14 -27
  66. package/src/sources/Evm.res +40 -1
  67. package/src/sources/Evm.res.mjs +94 -84
  68. package/src/sources/Fuel.res +40 -1
  69. package/src/sources/Fuel.res.mjs +36 -26
  70. package/src/sources/HyperFuel.res +41 -120
  71. package/src/sources/HyperFuel.res.mjs +42 -80
  72. package/src/sources/HyperFuel.resi +1 -24
  73. package/src/sources/HyperFuelClient.res +16 -297
  74. package/src/sources/HyperFuelClient.res.mjs +5 -4
  75. package/src/sources/HyperFuelSource.res +33 -8
  76. package/src/sources/HyperFuelSource.res.mjs +56 -10
  77. package/src/sources/HyperSyncSource.res +5 -3
  78. package/src/sources/HyperSyncSource.res.mjs +1 -1
  79. package/src/sources/RpcSource.res +2 -2
  80. package/src/sources/RpcSource.res.mjs +1 -1
  81. package/src/sources/SourceManager.res +8 -18
  82. package/src/sources/SourceManager.res.mjs +8 -5
  83. package/src/sources/SourceManager.resi +4 -1
  84. package/src/sources/Svm.res +18 -1
  85. package/src/sources/Svm.res.mjs +30 -22
  86. package/src/sources/SvmHyperSyncSource.res +1 -1
  87. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  88. package/src/tui/Tui.res +38 -36
  89. package/src/tui/Tui.res.mjs +51 -51
  90. package/src/ChainFetcher.res +0 -519
  91. package/src/ChainFetcher.res.mjs +0 -314
  92. package/src/ChainManager.res +0 -358
  93. package/src/ChainManager.res.mjs +0 -291
  94. package/src/Ctx.res +0 -6
  95. package/src/Ctx.res.mjs +0 -2
  96. package/src/GlobalState.res +0 -1056
  97. package/src/GlobalState.res.mjs +0 -1086
  98. package/src/GlobalStateManager.res +0 -57
  99. package/src/GlobalStateManager.res.mjs +0 -68
  100. package/src/GlobalStateManager.resi +0 -7
  101. package/src/Ports.res +0 -5
  102. package/src/Ports.res.mjs +0 -9
  103. package/src/adapters/MarkBatchProcessedAdapter.res +0 -5
  104. package/src/adapters/MarkBatchProcessedAdapter.res.mjs +0 -14
  105. package/src/sources/EnvioApiClient.res +0 -15
  106. package/src/sources/EnvioApiClient.res.mjs +0 -24
@@ -1,8 +1,5 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
4
-
5
- let isEarlierUnordered = Primitive_object.lessthan;
6
3
 
7
4
  function packEventIndex(blockNumber, logIndex) {
8
5
  let blockNumber$1 = BigInt(blockNumber);
@@ -12,7 +9,6 @@ function packEventIndex(blockNumber, logIndex) {
12
9
  }
13
10
 
14
11
  export {
15
- isEarlierUnordered,
16
12
  packEventIndex,
17
13
  }
18
14
  /* No side effect */
@@ -0,0 +1,10 @@
1
+ // Flush, then exit unless a reorg landed during the flush (which parks a
2
+ // rollback to recover instead).
3
+ let run = async (state: IndexerState.t) => {
4
+ ChainMetadata.stage(state)
5
+ await state->Writing.flush
6
+ if !(state->IndexerState.isStopped) && !(state->IndexerState.isResolvingReorg) {
7
+ Logging.info("Exiting with success")
8
+ NodeJs.process->NodeJs.exitWithCode(Success)
9
+ }
10
+ }
@@ -0,0 +1,22 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Logging from "./Logging.res.mjs";
4
+ import * as Writing from "./Writing.res.mjs";
5
+ import * as Process from "process";
6
+ import * as IndexerState from "./IndexerState.res.mjs";
7
+ import * as ChainMetadata from "./ChainMetadata.res.mjs";
8
+
9
+ async function run(state) {
10
+ ChainMetadata.stage(state);
11
+ await Writing.flush(state);
12
+ if (!IndexerState.isStopped(state) && !IndexerState.isResolvingReorg(state)) {
13
+ Logging.info("Exiting with success");
14
+ Process.exit(0);
15
+ return;
16
+ }
17
+ }
18
+
19
+ export {
20
+ run,
21
+ }
22
+ /* Logging Not a pure module */
@@ -496,9 +496,10 @@ type t = {
496
496
  blockLag: int,
497
497
  // Buffer of items ordered from earliest to latest
498
498
  buffer: array<Internal.item>,
499
- // How many items we should aim to have in the buffer
500
- // ready for processing
501
- targetBufferSize: int,
499
+ // Caps how far ahead onBlock items are pre-generated (set to 2x the batch
500
+ // size). Fetch depth is bounded separately by getNextQuery's bufferLimit, the
501
+ // chain's per-tick slice of the indexer-wide pool.
502
+ maxOnBlockBufferSize: int,
502
503
  onBlockConfigs: array<Internal.onBlockConfig>,
503
504
  knownHeight: int,
504
505
  firstEventBlock: option<int>,
@@ -554,7 +555,7 @@ let numAddresses = fetchState => fetchState.indexingAddresses->Utils.Dict.size
554
555
 
555
556
  // Appends Block items produced by the onBlock handlers for every block in
556
557
  // (fromBlock, maxBlockNumber] into mutItems and returns the new
557
- // latestOnBlockBlockNumber pointer. targetBufferSize bounds how many items
558
+ // latestOnBlockBlockNumber pointer. maxOnBlockBufferSize bounds how many items
558
559
  // are generated at once to prevent OOM.
559
560
  let appendOnBlockItems = (
560
561
  ~mutItems: array<Internal.item>,
@@ -562,7 +563,7 @@ let appendOnBlockItems = (
562
563
  ~indexerStartBlock,
563
564
  ~fromBlock,
564
565
  ~maxBlockNumber,
565
- ~targetBufferSize,
566
+ ~maxOnBlockBufferSize,
566
567
  ) => {
567
568
  let newItemsCounter = ref(0)
568
569
  let latestOnBlockBlockNumber = ref(fromBlock)
@@ -573,7 +574,7 @@ let appendOnBlockItems = (
573
574
  while (
574
575
  latestOnBlockBlockNumber.contents < maxBlockNumber &&
575
576
  // Additional safeguard to prevent OOM
576
- newItemsCounter.contents <= targetBufferSize
577
+ newItemsCounter.contents <= maxOnBlockBufferSize
577
578
  ) {
578
579
  let blockNumber = latestOnBlockBlockNumber.contents + 1
579
580
  latestOnBlockBlockNumber := blockNumber
@@ -627,7 +628,7 @@ let updateInternal = (
627
628
  | [] => knownHeight
628
629
  | onBlockConfigs => {
629
630
  // Calculate the max block number we are going to create items for
630
- // Use targetBufferSize to get the last target item in the buffer
631
+ // Use maxOnBlockBufferSize to get the last target item in the buffer
631
632
  //
632
633
  // mutItems is not very reliable, since it might not be sorted,
633
634
  // but the chances for it happen are very low and not critical
@@ -636,7 +637,7 @@ let updateInternal = (
636
637
  let maxBlockNumber = switch switch mutItemsRef.contents {
637
638
  | Some(mutItems) => mutItems
638
639
  | None => fetchState.buffer
639
- }->Array.get(fetchState.targetBufferSize - 1) {
640
+ }->Array.get(fetchState.maxOnBlockBufferSize - 1) {
640
641
  | Some(item) => item->Internal.getItemBlockNumber
641
642
  | None =>
642
643
  switch optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
@@ -657,7 +658,7 @@ let updateInternal = (
657
658
  ~indexerStartBlock=fetchState.startBlock,
658
659
  ~fromBlock=fetchState.latestOnBlockBlockNumber,
659
660
  ~maxBlockNumber,
660
- ~targetBufferSize=fetchState.targetBufferSize,
661
+ ~maxOnBlockBufferSize=fetchState.maxOnBlockBufferSize,
661
662
  )
662
663
  }
663
664
  }
@@ -669,7 +670,7 @@ let updateInternal = (
669
670
  normalSelection: fetchState.normalSelection,
670
671
  chainId: fetchState.chainId,
671
672
  onBlockConfigs: fetchState.onBlockConfigs,
672
- targetBufferSize: fetchState.targetBufferSize,
673
+ maxOnBlockBufferSize: fetchState.maxOnBlockBufferSize,
673
674
  optimizedPartitions,
674
675
  latestOnBlockBlockNumber,
675
676
  indexingAddresses,
@@ -1228,9 +1229,9 @@ let handleQueryResult = (
1228
1229
  // param-level analogue of EventRouter's srcAddress effectiveStartBlock check.
1229
1230
  let newItems = newItems->Array.filter(item =>
1230
1231
  switch item {
1231
- | Internal.Event({eventConfig, event, blockNumber}) =>
1232
+ | Internal.Event({eventConfig, payload, blockNumber}) =>
1232
1233
  switch eventConfig.clientAddressFilter {
1233
- | Some(filter) => filter(event, blockNumber, fetchState.indexingAddresses)
1234
+ | Some(filter) => filter(payload, blockNumber, fetchState.indexingAddresses)
1234
1235
  | None => true
1235
1236
  }
1236
1237
  | _ => true
@@ -1319,26 +1320,30 @@ let pushQueriesForRange = (
1319
1320
  | None => maxQueryBlockNumber
1320
1321
  }
1321
1322
  let chunkSize = Js.Math.ceil_int(chunkRange->Int.toFloat *. 1.8)
1322
- if rangeFromBlock + 2 * chunkSize - 1 <= maxBlock {
1323
- // Create 2 chunks of ceil(1.8 * chunkRange) each
1324
- queries->Array.push({
1325
- partitionId,
1326
- fromBlock: rangeFromBlock,
1327
- toBlock: Some(rangeFromBlock + chunkSize - 1),
1328
- isChunk: true,
1329
- selection,
1330
- addressesByContractName,
1331
- indexingAddresses,
1332
- })
1333
- queries->Array.push({
1334
- partitionId,
1335
- fromBlock: rangeFromBlock + chunkSize,
1336
- toBlock: Some(rangeFromBlock + 2 * chunkSize - 1),
1337
- isChunk: true,
1338
- selection,
1339
- addressesByContractName,
1340
- indexingAddresses,
1341
- })
1323
+ // Probe with two smaller chunks first so their responses come back
1324
+ // quickly and refresh the chunking heuristic, then three full-size chunks.
1325
+ let probeSize = Js.Math.ceil_int(chunkRange->Int.toFloat *. 0.9)
1326
+ let getChunkSize = chunkIdx => chunkIdx < 2 ? probeSize : chunkSize
1327
+ if rangeFromBlock + getChunkSize(0) + getChunkSize(1) - 1 <= maxBlock {
1328
+ let chunkFromBlock = ref(rangeFromBlock)
1329
+ let chunkIdx = ref(0)
1330
+ while (
1331
+ chunkIdx.contents < 5 &&
1332
+ chunkFromBlock.contents + getChunkSize(chunkIdx.contents) - 1 <= maxBlock
1333
+ ) {
1334
+ let chunkToBlock = chunkFromBlock.contents + getChunkSize(chunkIdx.contents) - 1
1335
+ queries->Array.push({
1336
+ partitionId,
1337
+ fromBlock: chunkFromBlock.contents,
1338
+ toBlock: Some(chunkToBlock),
1339
+ isChunk: true,
1340
+ selection,
1341
+ addressesByContractName,
1342
+ indexingAddresses,
1343
+ })
1344
+ chunkFromBlock := chunkToBlock + 1
1345
+ chunkIdx := chunkIdx.contents + 1
1346
+ }
1342
1347
  } else {
1343
1348
  // Not enough room for 2 chunks, fall back to a single query
1344
1349
  queries->Array.push({
@@ -1356,23 +1361,30 @@ let pushQueriesForRange = (
1356
1361
  }
1357
1362
  }
1358
1363
 
1364
+ // Most parallel in-flight chunk queries a single partition may have at once.
1365
+ let maxPendingChunksPerPartition = 10
1366
+
1359
1367
  let getNextQuery = (
1360
1368
  {
1361
1369
  buffer,
1362
1370
  optimizedPartitions,
1363
- targetBufferSize,
1364
1371
  indexingAddresses,
1365
1372
  blockLag,
1366
1373
  latestOnBlockBlockNumber,
1367
1374
  knownHeight,
1368
1375
  } as fetchState: t,
1369
1376
  ~concurrencyLimit,
1377
+ ~bufferLimit,
1370
1378
  ) => {
1371
1379
  let headBlockNumber = knownHeight - blockLag
1372
1380
  if headBlockNumber <= 0 {
1373
1381
  WaitingForNewBlock
1374
1382
  } else if concurrencyLimit === 0 {
1375
1383
  ReachedMaxConcurrency
1384
+ } else if bufferLimit <= 0 {
1385
+ // No room left in the shared buffer pool for this chain; wait for processing
1386
+ // to drain before fetching more.
1387
+ NothingToQuery
1376
1388
  } else {
1377
1389
  let isOnBlockBehindTheHead = latestOnBlockBlockNumber < headBlockNumber
1378
1390
  let shouldWaitForNewBlock = ref(
@@ -1383,13 +1395,12 @@ let getNextQuery = (
1383
1395
  !isOnBlockBehindTheHead,
1384
1396
  )
1385
1397
 
1386
- // We want to limit the buffer size to targetBufferSize (usually 3 * batchSize)
1387
- // To make sure the processing always has some buffer
1388
- // and not increase the memory usage too much
1389
- // If a partition fetched further
1390
- // it should be skipped until the buffer is consumed
1398
+ // Limit how far ahead we fetch to bufferLimit items (this chain's share of
1399
+ // the indexer-wide buffer pool) so processing always has buffer without
1400
+ // ballooning memory. A partition that fetched further is skipped until the
1401
+ // buffer drains.
1391
1402
  let maxQueryBlockNumber = {
1392
- switch buffer->Array.get(targetBufferSize - 1) {
1403
+ switch buffer->Array.get(bufferLimit - 1) {
1393
1404
  | Some(item) =>
1394
1405
  // Just in case check that we don't query beyond the current block
1395
1406
  Pervasives.min(item->Internal.getItemBlockNumber, knownHeight)
@@ -1406,8 +1417,9 @@ let getNextQuery = (
1406
1417
  let partitionId = optimizedPartitions.idsInAscOrder->Array.getUnsafe(idx)
1407
1418
  let p = optimizedPartitions.entities->Dict.getUnsafe(partitionId)
1408
1419
 
1420
+ let pendingCount = p.mutPendingQueries->Array.length
1409
1421
  let isBehindTheHead = p.latestFetchedBlock.blockNumber < headBlockNumber
1410
- let hasPendingQueries = p.mutPendingQueries->Utils.Array.notEmpty
1422
+ let hasPendingQueries = pendingCount > 0
1411
1423
 
1412
1424
  if hasPendingQueries || isBehindTheHead {
1413
1425
  // Even if there are some partitions waiting for the new block
@@ -1418,6 +1430,8 @@ let getNextQuery = (
1418
1430
  shouldWaitForNewBlock := false
1419
1431
  }
1420
1432
 
1433
+ let partitionQueriesStart = queries->Array.length
1434
+
1421
1435
  // Compute queryEndBlock for this partition
1422
1436
  let queryEndBlock = Utils.Math.minOptInt(fetchState.endBlock, p.mergeBlock)
1423
1437
  let queryEndBlock = switch blockLag {
@@ -1485,6 +1499,22 @@ let getNextQuery = (
1485
1499
  )
1486
1500
  }
1487
1501
 
1502
+ // Cap parallel in-flight chunks per partition so a single partition can't
1503
+ // drain the whole concurrency budget (especially the high realtime one).
1504
+ // Keep the earliest new chunks; the furthest-ahead ones wait for the next
1505
+ // round once these resolve.
1506
+ let maxNewChunks = Pervasives.max(0, maxPendingChunksPerPartition - pendingCount)
1507
+ let generatedCount = queries->Array.length - partitionQueriesStart
1508
+ if generatedCount > maxNewChunks {
1509
+ queries
1510
+ ->Array.splice(
1511
+ ~start=partitionQueriesStart + maxNewChunks,
1512
+ ~remove=generatedCount - maxNewChunks,
1513
+ ~insert=[],
1514
+ )
1515
+ ->ignore
1516
+ }
1517
+
1488
1518
  idxRef := idxRef.contents + 1
1489
1519
  }
1490
1520
 
@@ -1547,7 +1577,7 @@ let make = (
1547
1577
  ~addresses: array<Internal.indexingAddress>,
1548
1578
  ~maxAddrInPartition,
1549
1579
  ~chainId,
1550
- ~targetBufferSize,
1580
+ ~maxOnBlockBufferSize,
1551
1581
  ~knownHeight,
1552
1582
  ~progressBlockNumber=startBlock - 1,
1553
1583
  ~onBlockConfigs=[],
@@ -1696,7 +1726,7 @@ let make = (
1696
1726
  ~indexerStartBlock=startBlock,
1697
1727
  ~fromBlock=progressBlockNumber,
1698
1728
  ~maxBlockNumber,
1699
- ~targetBufferSize,
1729
+ ~maxOnBlockBufferSize,
1700
1730
  )
1701
1731
  } else {
1702
1732
  progressBlockNumber
@@ -1713,7 +1743,7 @@ let make = (
1713
1743
  indexingAddresses,
1714
1744
  blockLag,
1715
1745
  onBlockConfigs,
1716
- targetBufferSize,
1746
+ maxOnBlockBufferSize,
1717
1747
  knownHeight,
1718
1748
  buffer,
1719
1749
  firstEventBlock,
@@ -1737,6 +1767,25 @@ let make = (
1737
1767
 
1738
1768
  let bufferSize = ({buffer}: t) => buffer->Array.length
1739
1769
 
1770
+ // Number of buffered items at or below the ready frontier (processable now,
1771
+ // i.e. not stuck behind a gap from a lagging partition or out-of-order chunk).
1772
+ // The buffer is kept sorted, so binary-search the frontier in O(log n).
1773
+ let bufferReadyCount = (fetchState: t) => {
1774
+ let frontier = fetchState->bufferBlockNumber
1775
+ let buffer = fetchState.buffer
1776
+ let lo = ref(0)
1777
+ let hi = ref(buffer->Array.length)
1778
+ while lo.contents < hi.contents {
1779
+ let mid = (lo.contents + hi.contents) / 2
1780
+ if buffer->Array.getUnsafe(mid)->Internal.getItemBlockNumber <= frontier {
1781
+ lo := mid + 1
1782
+ } else {
1783
+ hi := mid
1784
+ }
1785
+ }
1786
+ lo.contents
1787
+ }
1788
+
1740
1789
  let rollbackPendingQueries = (mutPendingQueries: array<pendingQuery>, ~targetBlockNumber) => {
1741
1790
  // - Remove queries where fromBlock > target
1742
1791
  // - Cap fetchedBlock at target where fetchedBlock > target
@@ -1935,6 +1984,18 @@ let isActivelyIndexing = ({endBlock} as fetchState: t) => {
1935
1984
  }
1936
1985
  }
1937
1986
 
1987
+ // True once the fetch frontier has reached the (lagged) head or endBlock,
1988
+ // regardless of whether the buffer has been consumed yet. Unlike
1989
+ // isReadyToEnterReorgThreshold, fetched-but-unprocessed items still count.
1990
+ let isFetchingAtHead = ({endBlock, blockLag, knownHeight} as fetchState: t) => {
1991
+ let bufferBlockNumber = fetchState->bufferBlockNumber
1992
+ knownHeight !== 0 &&
1993
+ switch endBlock {
1994
+ | Some(endBlock) if bufferBlockNumber >= endBlock => true
1995
+ | _ => bufferBlockNumber >= knownHeight - blockLag
1996
+ }
1997
+ }
1998
+
1938
1999
  let isReadyToEnterReorgThreshold = ({endBlock, blockLag, buffer, knownHeight} as fetchState: t) => {
1939
2000
  let bufferBlockNumber = fetchState->bufferBlockNumber
1940
2001
  knownHeight !== 0 &&
@@ -1945,7 +2006,26 @@ let isReadyToEnterReorgThreshold = ({endBlock, blockLag, buffer, knownHeight} as
1945
2006
  buffer->Utils.Array.isEmpty
1946
2007
  }
1947
2008
 
1948
- let sortForUnorderedBatch = {
2009
+ // Lower progress percentage = further behind = higher priority. Shared by the
2010
+ // batch ordering and the cross-chain fetch priority.
2011
+ let getProgressPercentage = (fetchState: t) => {
2012
+ switch fetchState.firstEventBlock {
2013
+ | None => 0.
2014
+ | Some(firstEventBlock) =>
2015
+ let totalRange = fetchState.knownHeight - firstEventBlock
2016
+ if totalRange <= 0 {
2017
+ 0.
2018
+ } else {
2019
+ let progress = switch fetchState.buffer->Array.get(0) {
2020
+ | Some(item) => item->Internal.getItemBlockNumber - firstEventBlock
2021
+ | None => fetchState->bufferBlockNumber - firstEventBlock
2022
+ }
2023
+ progress->Int.toFloat /. totalRange->Int.toFloat
2024
+ }
2025
+ }
2026
+ }
2027
+
2028
+ let sortForBatch = {
1949
2029
  let hasFullBatch = ({buffer} as fetchState: t, ~batchSizeTarget) => {
1950
2030
  switch buffer->Array.get(batchSizeTarget - 1) {
1951
2031
  | Some(item) => item->Internal.getItemBlockNumber <= fetchState->bufferBlockNumber
@@ -1953,24 +2033,6 @@ let sortForUnorderedBatch = {
1953
2033
  }
1954
2034
  }
1955
2035
 
1956
- // Lower progress percentage = further behind = higher priority
1957
- let getProgressPercentage = (fetchState: t) => {
1958
- switch fetchState.firstEventBlock {
1959
- | None => 0.
1960
- | Some(firstEventBlock) =>
1961
- let totalRange = fetchState.knownHeight - firstEventBlock
1962
- if totalRange <= 0 {
1963
- 0.
1964
- } else {
1965
- let progress = switch fetchState.buffer->Array.get(0) {
1966
- | Some(item) => item->Internal.getItemBlockNumber - firstEventBlock
1967
- | None => fetchState->bufferBlockNumber - firstEventBlock
1968
- }
1969
- progress->Int.toFloat /. totalRange->Int.toFloat
1970
- }
1971
- }
1972
- }
1973
-
1974
2036
  (fetchStates: array<t>, ~batchSizeTarget: int) => {
1975
2037
  let copied = fetchStates->Array.copy
1976
2038
  copied->Array.sort((a: t, b: t) => {