envio 3.3.0-alpha.10 → 3.3.0-alpha.11

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 (57) hide show
  1. package/licenses/CLA.md +35 -0
  2. package/licenses/EULA.md +67 -0
  3. package/licenses/LICENSE.md +45 -0
  4. package/licenses/README.md +35 -0
  5. package/package.json +9 -8
  6. package/src/Batch.res.mjs +1 -1
  7. package/src/ChainFetching.res +13 -10
  8. package/src/ChainFetching.res.mjs +3 -4
  9. package/src/ChainState.res +45 -30
  10. package/src/ChainState.res.mjs +22 -8
  11. package/src/ChainState.resi +5 -0
  12. package/src/Config.res +9 -5
  13. package/src/Config.res.mjs +2 -2
  14. package/src/Core.res +20 -0
  15. package/src/Core.res.mjs +12 -0
  16. package/src/CrossChainState.res +18 -1
  17. package/src/CrossChainState.res.mjs +2 -1
  18. package/src/EventConfigBuilder.res +21 -46
  19. package/src/EventConfigBuilder.res.mjs +18 -25
  20. package/src/EventProcessing.res +8 -5
  21. package/src/EventProcessing.res.mjs +2 -1
  22. package/src/FetchState.res +344 -263
  23. package/src/FetchState.res.mjs +209 -131
  24. package/src/HandlerRegister.res +3 -1
  25. package/src/HandlerRegister.res.mjs +3 -2
  26. package/src/Internal.res +11 -2
  27. package/src/LogSelection.res +0 -62
  28. package/src/LogSelection.res.mjs +0 -74
  29. package/src/RawEvent.res +2 -2
  30. package/src/SimulateDeadInputTracker.res +1 -1
  31. package/src/SimulateItems.res +38 -6
  32. package/src/SimulateItems.res.mjs +28 -9
  33. package/src/TestIndexer.res +2 -2
  34. package/src/TestIndexer.res.mjs +2 -2
  35. package/src/TopicFilter.res +1 -25
  36. package/src/TopicFilter.res.mjs +0 -74
  37. package/src/bindings/Viem.res +0 -5
  38. package/src/sources/EventRouter.res +0 -21
  39. package/src/sources/EventRouter.res.mjs +0 -12
  40. package/src/sources/EvmChain.res +2 -27
  41. package/src/sources/EvmChain.res.mjs +2 -23
  42. package/src/sources/EvmRpcClient.res +12 -15
  43. package/src/sources/EvmRpcClient.res.mjs +3 -3
  44. package/src/sources/HyperSync.res +9 -38
  45. package/src/sources/HyperSync.res.mjs +16 -28
  46. package/src/sources/HyperSync.resi +2 -2
  47. package/src/sources/HyperSyncClient.res +88 -11
  48. package/src/sources/HyperSyncClient.res.mjs +39 -6
  49. package/src/sources/HyperSyncSource.res +18 -199
  50. package/src/sources/HyperSyncSource.res.mjs +9 -128
  51. package/src/sources/Rpc.res +0 -32
  52. package/src/sources/Rpc.res.mjs +1 -46
  53. package/src/sources/RpcSource.res +29 -175
  54. package/src/sources/RpcSource.res.mjs +32 -110
  55. package/src/sources/SimulateSource.res +37 -19
  56. package/src/sources/SimulateSource.res.mjs +27 -10
  57. package/src/sources/SvmHyperSyncSource.res +3 -3
@@ -484,13 +484,90 @@ function bufferReadyCount(fetchState) {
484
484
  return lo;
485
485
  }
486
486
 
487
+ function getRegistrationIndex(item) {
488
+ if (item.kind === 0) {
489
+ return item.onEventRegistration.index;
490
+ } else {
491
+ return item.onBlockRegistration.index;
492
+ }
493
+ }
494
+
487
495
  function compareBufferItem(a, b) {
488
- let blockOrdering = Primitive_int.compare(a.blockNumber, b.blockNumber);
489
- if (blockOrdering === 0) {
490
- return Primitive_int.compare(a.logIndex, b.logIndex);
496
+ let ba = a.blockNumber;
497
+ let bb = b.blockNumber;
498
+ if (ba !== bb) {
499
+ if (ba < bb) {
500
+ return -1;
501
+ } else {
502
+ return 1;
503
+ }
504
+ }
505
+ let la = a.logIndex;
506
+ let lb = b.logIndex;
507
+ if (la !== lb) {
508
+ if (la < lb) {
509
+ return -1;
510
+ } else {
511
+ return 1;
512
+ }
513
+ }
514
+ let ia = getRegistrationIndex(a);
515
+ let ib = getRegistrationIndex(b);
516
+ if (ia < ib) {
517
+ return -1;
518
+ } else if (ia > ib) {
519
+ return 1;
491
520
  } else {
492
- return blockOrdering;
521
+ return 0;
522
+ }
523
+ }
524
+
525
+ function mergeIntoBuffer(buffer, newItems) {
526
+ let n = newItems.length;
527
+ for (let i = 1; i < n; ++i) {
528
+ let x = newItems[i];
529
+ let j = i - 1 | 0;
530
+ while (j >= 0 && compareBufferItem(newItems[j], x) > 0) {
531
+ newItems[j + 1 | 0] = newItems[j];
532
+ j = j - 1 | 0;
533
+ };
534
+ newItems[j + 1 | 0] = x;
493
535
  }
536
+ let m = buffer.length;
537
+ let merged = [];
538
+ let last = {
539
+ contents: undefined
540
+ };
541
+ let push = item => {
542
+ let l = last.contents;
543
+ if (l !== undefined && compareBufferItem(l, item) === 0) {
544
+ return;
545
+ }
546
+ merged.push(item);
547
+ last.contents = item;
548
+ };
549
+ let i$1 = 0;
550
+ let j$1 = 0;
551
+ while (i$1 < m && j$1 < n) {
552
+ let a = buffer[i$1];
553
+ let b = newItems[j$1];
554
+ if (compareBufferItem(a, b) <= 0) {
555
+ push(a);
556
+ i$1 = i$1 + 1 | 0;
557
+ } else {
558
+ push(b);
559
+ j$1 = j$1 + 1 | 0;
560
+ }
561
+ };
562
+ while (i$1 < m) {
563
+ push(buffer[i$1]);
564
+ i$1 = i$1 + 1 | 0;
565
+ };
566
+ while (j$1 < n) {
567
+ push(newItems[j$1]);
568
+ j$1 = j$1 + 1 | 0;
569
+ };
570
+ return merged;
494
571
  }
495
572
 
496
573
  function appendOnBlockItems(mutItems, onBlockRegistrations, indexerStartBlock, fromBlock, maxBlockNumber, maxOnBlockBufferSize) {
@@ -522,18 +599,19 @@ function appendOnBlockItems(mutItems, onBlockRegistrations, indexerStartBlock, f
522
599
  return latestOnBlockBlockNumber;
523
600
  }
524
601
 
525
- function updateInternal(fetchState, optimizedPartitionsOpt, mutItems, blockLagOpt, knownHeightOpt) {
602
+ function updateInternal(fetchState, optimizedPartitionsOpt, mutItems, mutItemsSortedOpt, blockLagOpt, knownHeightOpt) {
526
603
  let optimizedPartitions = optimizedPartitionsOpt !== undefined ? optimizedPartitionsOpt : fetchState.optimizedPartitions;
604
+ let mutItemsSorted = mutItemsSortedOpt !== undefined ? mutItemsSortedOpt : false;
527
605
  let blockLag = blockLagOpt !== undefined ? blockLagOpt : fetchState.blockLag;
528
606
  let knownHeight = knownHeightOpt !== undefined ? knownHeightOpt : fetchState.knownHeight;
529
- let mutItemsRef = mutItems;
607
+ let base = mutItems !== undefined ? (
608
+ mutItemsSorted ? mutItems : mergeIntoBuffer([], mutItems)
609
+ ) : fetchState.buffer;
610
+ let blockItems = [];
530
611
  let onBlockRegistrations = fetchState.onBlockRegistrations;
531
612
  let latestOnBlockBlockNumber;
532
613
  if (onBlockRegistrations.length !== 0) {
533
- let mutItems$1 = mutItemsRef;
534
- let item = (
535
- mutItems$1 !== undefined ? mutItems$1 : fetchState.buffer
536
- )[fetchState.maxOnBlockBufferSize - 1 | 0];
614
+ let item = base[fetchState.maxOnBlockBufferSize - 1 | 0];
537
615
  let maxBlockNumber;
538
616
  if (item !== undefined) {
539
617
  maxBlockNumber = item.blockNumber;
@@ -542,20 +620,16 @@ function updateInternal(fetchState, optimizedPartitionsOpt, mutItems, blockLagOp
542
620
  let latestFullyFetchedBlock = id !== undefined ? optimizedPartitions.entities[id].latestFetchedBlock : undefined;
543
621
  maxBlockNumber = latestFullyFetchedBlock !== undefined ? latestFullyFetchedBlock.blockNumber : knownHeight;
544
622
  }
545
- let mutItems$2 = mutItemsRef;
546
- let mutItems$3 = mutItems$2 !== undefined ? mutItems$2 : fetchState.buffer.slice();
547
- mutItemsRef = mutItems$3;
548
- latestOnBlockBlockNumber = appendOnBlockItems(mutItems$3, onBlockRegistrations, fetchState.startBlock, fetchState.latestOnBlockBlockNumber, maxBlockNumber, fetchState.maxOnBlockBufferSize);
623
+ latestOnBlockBlockNumber = appendOnBlockItems(blockItems, onBlockRegistrations, fetchState.startBlock, fetchState.latestOnBlockBlockNumber, maxBlockNumber, fetchState.maxOnBlockBufferSize);
549
624
  } else {
550
625
  latestOnBlockBlockNumber = knownHeight;
551
626
  }
552
- let mutItems$4 = mutItemsRef;
553
627
  let updatedFetchState_startBlock = fetchState.startBlock;
554
628
  let updatedFetchState_endBlock = fetchState.endBlock;
555
629
  let updatedFetchState_normalSelection = fetchState.normalSelection;
556
630
  let updatedFetchState_contractConfigs = fetchState.contractConfigs;
557
631
  let updatedFetchState_chainId = fetchState.chainId;
558
- let updatedFetchState_buffer = mutItems$4 !== undefined ? (mutItems$4.sort(compareBufferItem), mutItems$4) : fetchState.buffer;
632
+ let updatedFetchState_buffer = blockItems.length !== 0 ? mergeIntoBuffer(base, blockItems) : base;
559
633
  let updatedFetchState_maxOnBlockBufferSize = fetchState.maxOnBlockBufferSize;
560
634
  let updatedFetchState_onBlockRegistrations = fetchState.onBlockRegistrations;
561
635
  let updatedFetchState_firstEventBlock = fetchState.firstEventBlock;
@@ -937,11 +1011,11 @@ function registerDynamicContracts(fetchState, indexingAddresses, items) {
937
1011
  }
938
1012
  IndexingAddresses.register(indexingAddresses, noEventsAddresses);
939
1013
  let optimizedPartitions = createPartitionsFromIndexingAddresses(registeringContractsByContract, dynamicContractsRef, fetchState.normalSelection, fetchState.optimizedPartitions.maxAddrInPartition, fetchState.optimizedPartitions.nextPartitionIndex + newPartitions.length | 0, mutExistingPartitions.concat(newPartitions), 0);
940
- return updateInternal(fetchState, optimizedPartitions, undefined, undefined, undefined);
1014
+ return updateInternal(fetchState, optimizedPartitions, undefined, undefined, undefined, undefined);
941
1015
  }
942
1016
 
943
- function handleQueryResult(fetchState, indexingAddresses, query, latestFetchedBlock, newItems) {
944
- let newItems$1 = newItems.filter(item => {
1017
+ function filterByClientAddress(items, indexingAddresses) {
1018
+ return items.filter(item => {
945
1019
  if (item.kind !== 0) {
946
1020
  return true;
947
1021
  }
@@ -952,7 +1026,10 @@ function handleQueryResult(fetchState, indexingAddresses, query, latestFetchedBl
952
1026
  return true;
953
1027
  }
954
1028
  });
955
- return updateInternal(fetchState, handleQueryResponse(fetchState.optimizedPartitions, query, fetchState.knownHeight, newItems$1.length, latestFetchedBlock), newItems$1.length !== 0 ? fetchState.buffer.concat(newItems$1) : undefined, undefined, undefined);
1029
+ }
1030
+
1031
+ function handleQueryResult(fetchState, query, latestFetchedBlock, newItems) {
1032
+ return updateInternal(fetchState, handleQueryResponse(fetchState.optimizedPartitions, query, fetchState.knownHeight, newItems.length, latestFetchedBlock), newItems.length !== 0 ? mergeIntoBuffer(fetchState.buffer, newItems) : undefined, true, undefined, undefined);
956
1033
  }
957
1034
 
958
1035
  function startFetchingQueries(param, queries) {
@@ -1051,24 +1128,6 @@ function pushGapFillQueries(queries, partitionId, rangeFromBlock, rangeEndBlock,
1051
1128
  return cost.contents;
1052
1129
  }
1053
1130
 
1054
- function waterLevel(budget, footprints) {
1055
- let sorted = footprints.toSorted(Primitive_float.compare);
1056
- let n = sorted.length;
1057
- let prefix = 0;
1058
- let level;
1059
- let idx = 0;
1060
- while (level === undefined && idx < n) {
1061
- let i = idx;
1062
- prefix = prefix + sorted[i];
1063
- let candidate = (budget + prefix) / (i + 1 | 0);
1064
- if (i === (n - 1 | 0) || candidate <= sorted[i + 1 | 0]) {
1065
- level = candidate;
1066
- }
1067
- idx = idx + 1 | 0;
1068
- };
1069
- return Stdlib_Option.getOr(level, 0);
1070
- }
1071
-
1072
1131
  function getNextQuery(param, chainTargetBlock, chainTargetItems, $staropt$star) {
1073
1132
  let knownHeight = param.knownHeight;
1074
1133
  let blockLag = param.blockLag;
@@ -1100,42 +1159,42 @@ function getNextQuery(param, chainTargetBlock, chainTargetItems, $staropt$star)
1100
1159
  return queryEndBlock;
1101
1160
  }
1102
1161
  };
1103
- let existingReservedByPartition = {};
1104
1162
  let chainReserved = 0;
1163
+ let reservations = [];
1164
+ let partitionIndexById = {};
1165
+ let candidates = [];
1166
+ let fillStates = [];
1105
1167
  for (let idx$1 = 0; idx$1 < partitionsCount; ++idx$1) {
1106
1168
  let partitionId$1 = optimizedPartitions.idsInAscOrder[idx$1];
1107
1169
  let p$1 = optimizedPartitions.entities[partitionId$1];
1108
- let cost = 0;
1109
- for (let pqIdx = 0, pqIdx_finish = p$1.mutPendingQueries.length; pqIdx < pqIdx_finish; ++pqIdx) {
1110
- cost = cost + p$1.mutPendingQueries[pqIdx].itemsEst;
1170
+ partitionIndexById[partitionId$1] = idx$1;
1171
+ let pendingCount = p$1.mutPendingQueries.length;
1172
+ for (let pqIdx = 0; pqIdx < pendingCount; ++pqIdx) {
1173
+ let pq = p$1.mutPendingQueries[pqIdx];
1174
+ if (pq.fetchedBlock === undefined) {
1175
+ chainReserved = chainReserved + pq.itemsEst;
1176
+ reservations.push([
1177
+ pq.fromBlock,
1178
+ pq.itemsEst
1179
+ ]);
1180
+ }
1111
1181
  }
1112
- existingReservedByPartition[partitionId$1] = cost;
1113
- chainReserved = chainReserved + cost;
1114
- }
1115
- let fillStates = [];
1116
- let gapFillCost = 0;
1117
- for (let idx$2 = 0; idx$2 < partitionsCount; ++idx$2) {
1118
- let partitionId$2 = optimizedPartitions.idsInAscOrder[idx$2];
1119
- let p$2 = optimizedPartitions.entities[partitionId$2];
1120
- let bucket = queriesByPartitionIndex[idx$2];
1121
- let pendingCount = p$2.mutPendingQueries.length;
1122
- let queryEndBlock = computeQueryEndBlock(p$2);
1123
- let maybeChunkRange = getMinHistoryRange(p$2);
1124
- let cursor = p$2.latestFetchedBlock.blockNumber + 1 | 0;
1182
+ let queryEndBlock = computeQueryEndBlock(p$1);
1183
+ let maybeChunkRange = getMinHistoryRange(p$1);
1184
+ let cursor = p$1.latestFetchedBlock.blockNumber + 1 | 0;
1125
1185
  let canContinue = true;
1126
1186
  let chunksUsedThisCall = 0;
1127
1187
  let pqIdx$1 = 0;
1128
1188
  while (pqIdx$1 < pendingCount && canContinue) {
1129
- let pq = p$2.mutPendingQueries[pqIdx$1];
1130
- if (pq.fromBlock > cursor) {
1131
- let beforeLen = bucket.length;
1132
- let cost$1 = pushGapFillQueries(bucket, partitionId$2, cursor, Utils.$$Math.minOptInt(pq.fromBlock - 1 | 0, queryEndBlock), knownHeight, chainTargetBlock, maybeChunkRange, (12 - pendingCount | 0) - chunksUsedThisCall | 0, p$2, chainTargetItems / partitionsCount, chunkItemsMultiplier, p$2.selection, p$2.addressesByContractName);
1133
- chunksUsedThisCall = chunksUsedThisCall + (bucket.length - beforeLen | 0) | 0;
1134
- gapFillCost = gapFillCost + cost$1;
1189
+ let pq$1 = p$1.mutPendingQueries[pqIdx$1];
1190
+ if (pq$1.fromBlock > cursor) {
1191
+ let beforeLen = candidates.length;
1192
+ pushGapFillQueries(candidates, partitionId$1, cursor, Utils.$$Math.minOptInt(pq$1.fromBlock - 1 | 0, queryEndBlock), knownHeight, chainTargetBlock, maybeChunkRange, (12 - pendingCount | 0) - chunksUsedThisCall | 0, p$1, chainTargetItems / partitionsCount, chunkItemsMultiplier, p$1.selection, p$1.addressesByContractName);
1193
+ chunksUsedThisCall = chunksUsedThisCall + (candidates.length - beforeLen | 0) | 0;
1135
1194
  }
1136
- let toBlock = pq.toBlock;
1137
- if (toBlock !== undefined && pq.isChunk) {
1138
- let match = pq.fetchedBlock;
1195
+ let toBlock = pq$1.toBlock;
1196
+ if (toBlock !== undefined && pq$1.isChunk) {
1197
+ let match = pq$1.fetchedBlock;
1139
1198
  if (match !== undefined) {
1140
1199
  let blockNumber = match.blockNumber;
1141
1200
  cursor = blockNumber < toBlock ? blockNumber + 1 | 0 : toBlock + 1 | 0;
@@ -1149,26 +1208,17 @@ function getNextQuery(param, chainTargetBlock, chainTargetItems, $staropt$star)
1149
1208
  };
1150
1209
  if (canContinue) {
1151
1210
  fillStates.push({
1152
- partitionId: partitionId$2,
1153
- p: p$2,
1211
+ partitionId: partitionId$1,
1212
+ p: p$1,
1154
1213
  cursor: cursor,
1155
1214
  chunksUsedThisCall: chunksUsedThisCall,
1156
1215
  pendingCount: pendingCount,
1157
1216
  queryEndBlock: queryEndBlock,
1158
- maybeChunkRange: maybeChunkRange,
1159
- bucket: bucket
1217
+ maybeChunkRange: maybeChunkRange
1160
1218
  });
1161
1219
  }
1162
1220
  }
1163
- let rangeItemsTarget = Primitive_float.max(0, chainTargetItems - chainReserved - gapFillCost);
1164
- let reservedByPartition = {};
1165
- fillStates.forEach(fs => {
1166
- let cost = existingReservedByPartition[fs.partitionId];
1167
- for (let i = 0, i_finish = fs.bucket.length; i < i_finish; ++i) {
1168
- cost = cost + fs.bucket[i].itemsEst;
1169
- }
1170
- reservedByPartition[fs.partitionId] = cost;
1171
- });
1221
+ let freshBudget = Primitive_float.max(0, chainTargetItems - chainReserved);
1172
1222
  let isInRange = fs => {
1173
1223
  let tmp = false;
1174
1224
  if (fs.cursor <= chainTargetBlock) {
@@ -1182,7 +1232,18 @@ function getNextQuery(param, chainTargetBlock, chainTargetItems, $staropt$star)
1182
1232
  }
1183
1233
  };
1184
1234
  let inRangeStates = fillStates.filter(isInRange);
1185
- let emitQueries = (fs, budget) => {
1235
+ let inRangeCount = inRangeStates.length;
1236
+ let probeShare = inRangeCount === 0 ? 0 : freshBudget / inRangeCount;
1237
+ let frontierCursor = Stdlib_Array.reduce(inRangeStates, chainTargetBlock, (min, fs) => {
1238
+ if (fs.cursor < min) {
1239
+ return fs.cursor;
1240
+ } else {
1241
+ return min;
1242
+ }
1243
+ });
1244
+ let rangeToTarget = (chainTargetBlock - frontierCursor | 0) + 1 | 0;
1245
+ let rangeTargetDensity = inRangeCount > 0 && rangeToTarget > 0 ? freshBudget / rangeToTarget : 0;
1246
+ inRangeStates.forEach(fs => {
1186
1247
  let p = fs.p;
1187
1248
  let eb = fs.queryEndBlock;
1188
1249
  let maxBlock = eb !== undefined ? eb : chainTargetBlock;
@@ -1191,39 +1252,33 @@ function getNextQuery(param, chainTargetBlock, chainTargetItems, $staropt$star)
1191
1252
  if (match !== undefined && match$1 !== undefined && match$1 > 0) {
1192
1253
  let chunkSize = Js_math.ceil_int(match * 1.8);
1193
1254
  let maxChunksRemaining = (12 - fs.pendingCount | 0) - fs.chunksUsedThisCall | 0;
1194
- let consumed = 0;
1255
+ let chunkStartCeiling = Primitive_int.min(maxBlock, chainTargetBlock);
1195
1256
  let created = 0;
1196
1257
  let chunkFromBlock = fs.cursor;
1197
- let budgetLeft = true;
1198
- while (budgetLeft && created < maxChunksRemaining && chunkFromBlock <= Primitive_int.min(maxBlock, chainTargetBlock)) {
1258
+ let generatedItems = 0;
1259
+ while (created < maxChunksRemaining && chunkFromBlock <= chunkStartCeiling && generatedItems <= freshBudget) {
1199
1260
  let chunkToBlock = Primitive_int.min((chunkFromBlock + chunkSize | 0) - 1 | 0, maxBlock);
1200
1261
  let rawEst = match$1 * ((chunkToBlock - chunkFromBlock | 0) + 1 | 0);
1201
1262
  let itemsEst = Primitive_int.max(1, Math.ceil(rawEst) | 0);
1202
1263
  let itemsTarget = Primitive_int.max(1, Math.ceil(rawEst * chunkItemsMultiplier) | 0);
1203
- if (consumed === 0 || consumed + itemsEst <= budget) {
1204
- fs.bucket.push({
1205
- partitionId: fs.partitionId,
1206
- fromBlock: chunkFromBlock,
1207
- toBlock: chunkToBlock,
1208
- isChunk: true,
1209
- itemsTarget: itemsTarget,
1210
- itemsEst: itemsEst,
1211
- selection: p.selection,
1212
- addressesByContractName: p.addressesByContractName
1213
- });
1214
- consumed = consumed + itemsEst;
1215
- chunkFromBlock = chunkToBlock + 1 | 0;
1216
- created = created + 1 | 0;
1217
- } else {
1218
- budgetLeft = false;
1219
- }
1264
+ candidates.push({
1265
+ partitionId: fs.partitionId,
1266
+ fromBlock: chunkFromBlock,
1267
+ toBlock: chunkToBlock,
1268
+ isChunk: true,
1269
+ itemsTarget: itemsTarget,
1270
+ itemsEst: itemsEst,
1271
+ selection: p.selection,
1272
+ addressesByContractName: p.addressesByContractName
1273
+ });
1274
+ generatedItems = generatedItems + itemsEst;
1275
+ chunkFromBlock = chunkToBlock + 1 | 0;
1276
+ created = created + 1 | 0;
1220
1277
  };
1221
- fs.cursor = chunkFromBlock;
1222
- fs.chunksUsedThisCall = fs.chunksUsedThisCall + created | 0;
1223
- return consumed;
1278
+ return;
1224
1279
  }
1225
- let itemsTarget$1 = Primitive_int.max(1, Math.round(budget) | 0);
1226
- fs.bucket.push({
1280
+ let itemsTarget$1 = rangeToTarget > 0 ? Primitive_int.max(1, Math.round(rangeTargetDensity * ((chainTargetBlock - fs.cursor | 0) + 1 | 0) / inRangeCount) | 0) : Primitive_int.max(1, Math.round(probeShare) | 0);
1281
+ candidates.push({
1227
1282
  partitionId: fs.partitionId,
1228
1283
  fromBlock: fs.cursor,
1229
1284
  toBlock: fs.queryEndBlock,
@@ -1233,32 +1288,53 @@ function getNextQuery(param, chainTargetBlock, chainTargetItems, $staropt$star)
1233
1288
  selection: p.selection,
1234
1289
  addressesByContractName: p.addressesByContractName
1235
1290
  });
1236
- fs.cursor = maxBlock + 1 | 0;
1237
- fs.chunksUsedThisCall = fs.chunksUsedThisCall + 1 | 0;
1238
- return itemsTarget$1;
1239
- };
1240
- let notFilledPartitions = inRangeStates;
1241
- let remainingBudget = {
1242
- contents: rangeItemsTarget
1243
- };
1244
- while (notFilledPartitions.length !== 0 && remainingBudget.contents > 0) {
1245
- let level = waterLevel(remainingBudget.contents, notFilledPartitions.map(fs => reservedByPartition[fs.partitionId]));
1246
- let next = [];
1247
- notFilledPartitions.forEach(fs => {
1248
- let reserved = reservedByPartition[fs.partitionId];
1249
- let budget = level - reserved;
1250
- if (budget <= 0) {
1251
- return;
1252
- }
1253
- let consumed = emitQueries(fs, budget);
1254
- reservedByPartition[fs.partitionId] = reserved + consumed;
1255
- remainingBudget.contents = remainingBudget.contents - consumed;
1256
- if (isInRange(fs)) {
1257
- next.push(fs);
1258
- return;
1291
+ });
1292
+ let acceptanceStream = [];
1293
+ candidates.forEach(query => {
1294
+ acceptanceStream.push([
1295
+ query.fromBlock,
1296
+ query.itemsEst,
1297
+ query
1298
+ ]);
1299
+ });
1300
+ reservations.forEach(param => {
1301
+ acceptanceStream.push([
1302
+ param[0],
1303
+ param[1],
1304
+ undefined
1305
+ ]);
1306
+ });
1307
+ acceptanceStream.sort((param, param$1) => {
1308
+ let bFrom = param$1[0];
1309
+ let aFrom = param[0];
1310
+ if (aFrom !== bFrom) {
1311
+ return Primitive_int.compare(aFrom, bFrom);
1312
+ }
1313
+ let bQuery = param$1[2];
1314
+ if (param[2] !== undefined) {
1315
+ if (bQuery !== undefined) {
1316
+ return 0;
1317
+ } else {
1318
+ return 1;
1259
1319
  }
1260
- });
1261
- notFilledPartitions = next;
1320
+ } else if (bQuery !== undefined) {
1321
+ return -1;
1322
+ } else {
1323
+ return 0;
1324
+ }
1325
+ });
1326
+ let streamCount = acceptanceStream.length;
1327
+ let remainingBudget = chainTargetItems;
1328
+ let acceptIdx = 0;
1329
+ while (remainingBudget > 0 && acceptIdx < streamCount) {
1330
+ let match$1 = acceptanceStream[acceptIdx];
1331
+ let maybeQuery = match$1[2];
1332
+ if (maybeQuery !== undefined) {
1333
+ let partitionIdx = partitionIndexById[maybeQuery.partitionId];
1334
+ queriesByPartitionIndex[partitionIdx].push(maybeQuery);
1335
+ }
1336
+ remainingBudget = remainingBudget - match$1[1];
1337
+ acceptIdx = acceptIdx + 1 | 0;
1262
1338
  };
1263
1339
  let queries = queriesByPartitionIndex.flat();
1264
1340
  if (Utils.$$Array.isEmpty(queries)) {
@@ -1525,7 +1601,7 @@ function rollback(fetchState, indexingAddresses, targetBlockNumber) {
1525
1601
  let tmp;
1526
1602
  tmp = item.kind === 0 ? item.blockNumber : item.blockNumber;
1527
1603
  return tmp <= targetBlockNumber;
1528
- }), undefined, undefined);
1604
+ }), true, undefined, undefined);
1529
1605
  }
1530
1606
 
1531
1607
  function resetPendingQueries(fetchState) {
@@ -1678,7 +1754,7 @@ function getProgressBlockNumberAt(fetchState, index) {
1678
1754
  function updateKnownHeight(fetchState, knownHeight) {
1679
1755
  if (knownHeight > fetchState.knownHeight) {
1680
1756
  Prometheus.IndexingKnownHeight.set(knownHeight, fetchState.chainId);
1681
- return updateInternal(fetchState, undefined, undefined, undefined, knownHeight);
1757
+ return updateInternal(fetchState, undefined, undefined, undefined, undefined, knownHeight);
1682
1758
  } else {
1683
1759
  return fetchState;
1684
1760
  }
@@ -1698,7 +1774,9 @@ export {
1698
1774
  bufferBlockNumber,
1699
1775
  bufferBlock,
1700
1776
  bufferReadyCount,
1777
+ getRegistrationIndex,
1701
1778
  compareBufferItem,
1779
+ mergeIntoBuffer,
1702
1780
  blockItemLogIndex,
1703
1781
  appendOnBlockItems,
1704
1782
  updateInternal,
@@ -1707,11 +1785,11 @@ export {
1707
1785
  addressesByContractNameGetAll,
1708
1786
  createPartitionsFromIndexingAddresses,
1709
1787
  registerDynamicContracts,
1788
+ filterByClientAddress,
1710
1789
  handleQueryResult,
1711
1790
  startFetchingQueries,
1712
1791
  maxPendingChunksPerPartition,
1713
1792
  pushGapFillQueries,
1714
- waterLevel,
1715
1793
  getNextQuery,
1716
1794
  hasReadyItem,
1717
1795
  getReadyItemsCount,
@@ -679,7 +679,9 @@ let finishRegistration = (~config: Config.t): registrationsByChainId => {
679
679
  config.ecosystem.name === Evm &&
680
680
  (registration->getResolvedWhere).topicSelections->Utils.Array.isEmpty
681
681
  if !isDroppedByWhere {
682
- onEventRegistrations->Array.push(registration)
682
+ onEventRegistrations
683
+ ->Array.push({...registration, index: onEventRegistrations->Array.length})
684
+ ->ignore
683
685
  }
684
686
  | None => ()
685
687
  }
@@ -388,10 +388,11 @@ function finishRegistration(config) {
388
388
  return;
389
389
  }
390
390
  let isDroppedByWhere = config.ecosystem.name === "evm" && Utils.$$Array.isEmpty(registration$1.resolvedWhere.topicSelections);
391
- if (!isDroppedByWhere) {
392
- onEventRegistrations.push(registration$1);
391
+ if (isDroppedByWhere) {
393
392
  return;
394
393
  }
394
+ let newrecord = {...registration$1};
395
+ onEventRegistrations.push((newrecord.index = onEventRegistrations.length, newrecord));
395
396
  });
396
397
  });
397
398
  registrationsByChainId[key] = {
package/src/Internal.res CHANGED
@@ -330,6 +330,9 @@ type eventPayload
330
330
  @get external getPayloadBlock: eventPayload => Nullable.t<eventBlock> = "block"
331
331
  @set external setPayloadBlock: (eventPayload, eventBlock) => unit = "block"
332
332
 
333
+ // The log's emitting address (EVM/Fuel; the program id carries it for SVM).
334
+ @get external getPayloadSrcAddress: eventPayload => Address.t = "srcAddress"
335
+
333
336
  type genericLoaderArgs<'event, 'context> = {
334
337
  event: 'event,
335
338
  context: 'context,
@@ -555,6 +558,11 @@ type svmInstructionEventConfig = {
555
558
  // must stay directly constructable), and the evm→base cast in sources is sound
556
559
  // by ecosystem homogeneity — an EVM chain only ever holds `evmOnEventRegistration`s.
557
560
  type onEventRegistration = {
561
+ // Chain-scoped sequential index — the registration's position in the
562
+ // chain's onEventRegistrations array, assigned when registration finishes
563
+ // (-1 until then). Native-routed items reference their registration by this
564
+ // index across the napi boundary; sources resolve it before creating an item.
565
+ index: int,
558
566
  eventConfig: eventConfig,
559
567
  handler: option<handler>,
560
568
  contractRegister: option<contractRegister>,
@@ -601,8 +609,9 @@ type indexingAddress = {
601
609
 
602
610
  type dcs = array<indexingAddress>
603
611
 
604
- // Duplicate the type from item
605
- // to make item properly unboxed
612
+ // Duplicate the type from item to keep item properly unboxed. Runtime event
613
+ // items carry the registration their source already resolved from the
614
+ // ChainState-owned registration array.
606
615
  type eventItem = private {
607
616
  kind: [#0],
608
617
  onEventRegistration: onEventRegistration,
@@ -1,65 +1,3 @@
1
- exception MissingRequiredTopic0
2
- let makeTopicSelection = (~topic0, ~topic1=[], ~topic2=[], ~topic3=[]): result<
3
- Internal.topicSelection,
4
- exn,
5
- > =>
6
- if topic0->Utils.Array.isEmpty {
7
- Error(MissingRequiredTopic0)
8
- } else {
9
- {
10
- Internal.topic0,
11
- topic1,
12
- topic2,
13
- topic3,
14
- }->Ok
15
- }
16
-
17
- let hasFilters = ({topic1, topic2, topic3}: Internal.topicSelection) => {
18
- [topic1, topic2, topic3]->Array.find(topic => !Utils.Array.isEmpty(topic))->Option.isSome
19
- }
20
-
21
- /**
22
- For a group of topic selections, if multiple only use topic0, then they can be compressed into one
23
- selection combining the topic0s
24
- */
25
- let compressTopicSelections = (topicSelections: array<Internal.topicSelection>) => {
26
- let topic0sOfSelectionsWithoutFilters = []
27
-
28
- let selectionsWithFilters = []
29
-
30
- topicSelections->Array.forEach(selection => {
31
- if selection->hasFilters {
32
- selectionsWithFilters->Array.push(selection)->ignore
33
- } else {
34
- selection.topic0->Array.forEach(topic0 => {
35
- topic0sOfSelectionsWithoutFilters->Array.push(topic0)->ignore
36
- })
37
- }
38
- })
39
-
40
- switch topic0sOfSelectionsWithoutFilters {
41
- | [] => selectionsWithFilters
42
- | topic0 =>
43
- let selectionWithoutFilters: Internal.topicSelection = {
44
- topic0,
45
- topic1: [],
46
- topic2: [],
47
- topic3: [],
48
- }
49
- Array.concat([selectionWithoutFilters], selectionsWithFilters)
50
- }
51
- }
52
-
53
- type t = {
54
- addresses: array<Address.t>,
55
- topicSelections: array<Internal.topicSelection>,
56
- }
57
-
58
- let make = (~addresses, ~topicSelections) => {
59
- let topicSelections = compressTopicSelections(topicSelections)
60
- {addresses, topicSelections}
61
- }
62
-
63
1
  // Expand a resolved topic selection into concrete topic values for a query:
64
2
  // `ContractAddresses` markers become the given partition addresses encoded as
65
3
  // topics; `Values` pass through.