envio 3.3.0-alpha.1 → 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 (143) hide show
  1. package/evm.schema.json +10 -0
  2. package/index.d.ts +45 -25
  3. package/licenses/CLA.md +35 -0
  4. package/licenses/EULA.md +67 -0
  5. package/licenses/LICENSE.md +45 -0
  6. package/licenses/README.md +35 -0
  7. package/package.json +10 -9
  8. package/src/Address.res +5 -2
  9. package/src/Address.res.mjs +3 -1
  10. package/src/Api.res +1 -1
  11. package/src/Api.res.mjs +1 -1
  12. package/src/Batch.res +0 -6
  13. package/src/Batch.res.mjs +1 -12
  14. package/src/BatchProcessing.res +7 -12
  15. package/src/BatchProcessing.res.mjs +8 -7
  16. package/src/Bin.res +3 -0
  17. package/src/Bin.res.mjs +4 -0
  18. package/src/ChainFetching.res +53 -16
  19. package/src/ChainFetching.res.mjs +37 -19
  20. package/src/ChainMetadata.res +1 -11
  21. package/src/ChainMetadata.res.mjs +1 -10
  22. package/src/ChainState.res +630 -161
  23. package/src/ChainState.res.mjs +438 -101
  24. package/src/ChainState.resi +77 -4
  25. package/src/Config.res +70 -38
  26. package/src/Config.res.mjs +52 -12
  27. package/src/ContractRegisterContext.res +2 -12
  28. package/src/ContractRegisterContext.res.mjs +3 -5
  29. package/src/Core.res +34 -3
  30. package/src/Core.res.mjs +12 -0
  31. package/src/CrossChainState.res +130 -89
  32. package/src/CrossChainState.res.mjs +66 -61
  33. package/src/CrossChainState.resi +1 -1
  34. package/src/Ecosystem.res +5 -6
  35. package/src/Ecosystem.res.mjs +3 -3
  36. package/src/Envio.res +17 -11
  37. package/src/EnvioGlobal.res +53 -0
  38. package/src/EnvioGlobal.res.mjs +31 -0
  39. package/src/EventConfigBuilder.res +191 -127
  40. package/src/EventConfigBuilder.res.mjs +116 -66
  41. package/src/EventProcessing.res +77 -28
  42. package/src/EventProcessing.res.mjs +56 -29
  43. package/src/ExitOnCaughtUp.res +10 -2
  44. package/src/ExitOnCaughtUp.res.mjs +10 -1
  45. package/src/FetchState.res +684 -415
  46. package/src/FetchState.res.mjs +505 -486
  47. package/src/HandlerLoader.res +8 -104
  48. package/src/HandlerLoader.res.mjs +2 -81
  49. package/src/HandlerRegister.res +520 -144
  50. package/src/HandlerRegister.res.mjs +286 -133
  51. package/src/HandlerRegister.resi +24 -8
  52. package/src/IndexerState.res +10 -3
  53. package/src/IndexerState.res.mjs +11 -4
  54. package/src/IndexerState.resi +2 -1
  55. package/src/IndexingAddresses.res +108 -0
  56. package/src/IndexingAddresses.res.mjs +101 -0
  57. package/src/IndexingAddresses.resi +34 -0
  58. package/src/Internal.res +166 -48
  59. package/src/Internal.res.mjs +30 -2
  60. package/src/LoadLayer.res +5 -5
  61. package/src/LoadLayer.res.mjs +6 -6
  62. package/src/LogSelection.res +92 -217
  63. package/src/LogSelection.res.mjs +95 -184
  64. package/src/Main.res +71 -236
  65. package/src/Main.res.mjs +60 -145
  66. package/src/Metrics.res +74 -0
  67. package/src/Metrics.res.mjs +75 -0
  68. package/src/PgStorage.res +4 -4
  69. package/src/PgStorage.res.mjs +5 -5
  70. package/src/Prometheus.res +10 -63
  71. package/src/Prometheus.res.mjs +124 -171
  72. package/src/PruneStaleHistory.res +2 -2
  73. package/src/PruneStaleHistory.res.mjs +3 -3
  74. package/src/RawEvent.res +7 -2
  75. package/src/RawEvent.res.mjs +4 -4
  76. package/src/Rollback.res +3 -3
  77. package/src/Rollback.res.mjs +4 -4
  78. package/src/RollbackCommit.res +4 -1
  79. package/src/RollbackCommit.res.mjs +3 -2
  80. package/src/SimulateDeadInputTracker.res +85 -0
  81. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  82. package/src/SimulateDeadInputTracker.resi +12 -0
  83. package/src/SimulateItems.res +128 -28
  84. package/src/SimulateItems.res.mjs +82 -40
  85. package/src/TestIndexer.res +55 -41
  86. package/src/TestIndexer.res.mjs +39 -32
  87. package/src/TopicFilter.res +1 -25
  88. package/src/TopicFilter.res.mjs +0 -74
  89. package/src/bindings/Performance.res +7 -0
  90. package/src/bindings/Performance.res.mjs +21 -0
  91. package/src/bindings/Performance.resi +7 -0
  92. package/src/bindings/Viem.res +0 -46
  93. package/src/bindings/Viem.res.mjs +1 -43
  94. package/src/sources/BlockStore.res +46 -0
  95. package/src/sources/BlockStore.res.mjs +24 -0
  96. package/src/sources/EventRouter.res +31 -49
  97. package/src/sources/EventRouter.res.mjs +12 -25
  98. package/src/sources/Evm.res +83 -72
  99. package/src/sources/Evm.res.mjs +53 -69
  100. package/src/sources/EvmChain.res +7 -34
  101. package/src/sources/EvmChain.res.mjs +6 -27
  102. package/src/sources/EvmRpcClient.res +71 -5
  103. package/src/sources/EvmRpcClient.res.mjs +13 -4
  104. package/src/sources/FieldMask.res +39 -0
  105. package/src/sources/FieldMask.res.mjs +42 -0
  106. package/src/sources/Fuel.res +9 -6
  107. package/src/sources/Fuel.res.mjs +5 -10
  108. package/src/sources/HyperFuelSource.res +46 -50
  109. package/src/sources/HyperFuelSource.res.mjs +64 -54
  110. package/src/sources/HyperSync.res +45 -42
  111. package/src/sources/HyperSync.res.mjs +68 -60
  112. package/src/sources/HyperSync.resi +14 -4
  113. package/src/sources/HyperSyncClient.res +107 -119
  114. package/src/sources/HyperSyncClient.res.mjs +36 -31
  115. package/src/sources/HyperSyncHeightStream.res +1 -8
  116. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  117. package/src/sources/HyperSyncSource.res +60 -254
  118. package/src/sources/HyperSyncSource.res.mjs +57 -180
  119. package/src/sources/Rpc.res +15 -79
  120. package/src/sources/Rpc.res.mjs +25 -101
  121. package/src/sources/RpcSource.res +221 -514
  122. package/src/sources/RpcSource.res.mjs +216 -411
  123. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  124. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  125. package/src/sources/SimulateSource.res +44 -20
  126. package/src/sources/SimulateSource.res.mjs +41 -14
  127. package/src/sources/Source.res +34 -6
  128. package/src/sources/SourceManager.res +77 -19
  129. package/src/sources/SourceManager.res.mjs +63 -21
  130. package/src/sources/SourceManager.resi +10 -0
  131. package/src/sources/Svm.res +31 -16
  132. package/src/sources/Svm.res.mjs +36 -13
  133. package/src/sources/SvmHyperSyncClient.res +5 -32
  134. package/src/sources/SvmHyperSyncSource.res +159 -134
  135. package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
  136. package/src/sources/TransactionStore.res +49 -0
  137. package/src/sources/TransactionStore.res.mjs +30 -0
  138. package/src/tui/Tui.res +13 -16
  139. package/src/tui/Tui.res.mjs +12 -14
  140. package/svm.schema.json +49 -37
  141. package/src/bindings/Hrtime.res +0 -58
  142. package/src/bindings/Hrtime.res.mjs +0 -90
  143. package/src/bindings/Hrtime.resi +0 -30
@@ -1,9 +1,8 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as Hrtime from "../bindings/Hrtime.res.mjs";
4
3
  import * as Source from "./Source.res.mjs";
5
- import * as Prometheus from "../Prometheus.res.mjs";
6
4
  import * as EventRouter from "./EventRouter.res.mjs";
5
+ import * as Performance from "../bindings/Performance.res.mjs";
7
6
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
8
7
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
9
8
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
@@ -166,7 +165,7 @@ function parseDecoded(d) {
166
165
  };
167
166
  }
168
167
 
169
- function toSvmInstruction(instr, programName, instructionName, transaction, logs, block) {
168
+ function toSvmInstruction(instr, programName, instructionName, logs) {
170
169
  return {
171
170
  programName: programName,
172
171
  instructionName: instructionName,
@@ -180,40 +179,14 @@ function toSvmInstruction(instr, programName, instructionName, transaction, logs
180
179
  d4: instr.d4,
181
180
  d8: instr.d8,
182
181
  params: Stdlib_Option.map(instr.decoded, parseDecoded),
183
- transaction: transaction,
184
- logs: logs,
185
- block: block
182
+ logs: logs
186
183
  };
187
184
  }
188
185
 
189
- function toSvmTransaction(tx) {
190
- return {
191
- signatures: tx.signatures,
192
- feePayer: Stdlib_Option.map(tx.feePayer, prim => prim),
193
- success: tx.success,
194
- err: tx.err,
195
- fee: Stdlib_Option.map(tx.fee, prim => BigInt(prim)),
196
- computeUnitsConsumed: Stdlib_Option.map(tx.computeUnitsConsumed, prim => BigInt(prim)),
197
- accountKeys: tx.accountKeys,
198
- recentBlockhash: tx.recentBlockhash,
199
- version: tx.version
200
- };
201
- }
202
-
203
- function toSvmTokenBalance(tb) {
204
- return {
205
- account: Stdlib_Option.map(tb.account, prim => prim),
206
- mint: Stdlib_Option.map(tb.mint, prim => prim),
207
- owner: Stdlib_Option.map(tb.owner, prim => prim),
208
- preAmount: tb.preAmount,
209
- postAmount: tb.postAmount
210
- };
211
- }
212
-
213
- function probeRouter(router, programId, instr, byteLengthsDesc, contractAddress, indexingAddresses) {
186
+ function probeRouter(router, programId, instr, byteLengthsDesc, contractAddress, contractNameByAddress) {
214
187
  let probe = dN => {
215
188
  let tag = EventRouter.getSvmEventId(programId, dN);
216
- return EventRouter.get(router, tag, contractAddress, instr.slot, indexingAddresses);
189
+ return EventRouter.get(router, tag, contractAddress, contractNameByAddress);
217
190
  };
218
191
  let result = Stdlib_Array.reduce(byteLengthsDesc, undefined, (acc, len) => {
219
192
  if (acc !== undefined) {
@@ -247,43 +220,109 @@ function probeRouter(router, programId, instr, byteLengthsDesc, contractAddress,
247
220
  }
248
221
  }
249
222
 
223
+ function toQueryTxField(field) {
224
+ switch (field) {
225
+ case "signatures" :
226
+ return "signatures";
227
+ case "feePayer" :
228
+ return "fee_payer";
229
+ case "success" :
230
+ return "success";
231
+ case "err" :
232
+ return "err";
233
+ case "fee" :
234
+ return "fee";
235
+ case "computeUnitsConsumed" :
236
+ return "compute_units_consumed";
237
+ case "accountKeys" :
238
+ return "account_keys";
239
+ case "recentBlockhash" :
240
+ return "recent_blockhash";
241
+ case "version" :
242
+ return "version";
243
+ case "transactionIndex" :
244
+ case "tokenBalances" :
245
+ return;
246
+ }
247
+ }
248
+
249
+ function toQueryBlockField(field) {
250
+ switch (field) {
251
+ case "height" :
252
+ return "block_height";
253
+ case "parentSlot" :
254
+ return "parent_slot";
255
+ case "parentHash" :
256
+ return "parent_blockhash";
257
+ default:
258
+ return;
259
+ }
260
+ }
261
+
250
262
  function make(param) {
251
- let eventConfigs = param.eventConfigs;
263
+ let onEventRegistrations = param.onEventRegistrations;
252
264
  let chain = param.chain;
253
- let name = "SvmHyperSync";
265
+ let eventConfigs = onEventRegistrations.map(reg => reg.eventConfig);
254
266
  let programSchemas = buildProgramSchemas(eventConfigs);
255
267
  let client = SvmHyperSyncClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, undefined, undefined, undefined, programSchemas.length !== 0 ? programSchemas : undefined);
256
- let match = EventRouter.fromSvmEventConfigsOrThrow(eventConfigs, chain);
268
+ let match = EventRouter.fromSvmEventConfigsOrThrow(onEventRegistrations, chain);
257
269
  let eventRouter = match[0];
258
270
  let orderingByProgram = {};
259
271
  match[1].forEach(o => {
260
272
  orderingByProgram[o.programId] = o.byteLengthsDesc;
261
273
  });
262
- let needsTransactions = eventConfigs.some(cfg => cfg.includeTransaction);
263
274
  let needsLogs = eventConfigs.some(cfg => cfg.includeLogs);
264
- let needsTokenBalances = eventConfigs.some(cfg => cfg.includeTokenBalances);
265
- let getItemsOrThrow = async (fromBlock, toBlock, param, indexingAddresses, knownHeight, param$1, param$2, retry, logger) => {
266
- let totalTimeRef = Hrtime.makeTimer();
267
- let pageFetchRef = Hrtime.makeTimer();
275
+ let selectedTxFields = new Set();
276
+ eventConfigs.forEach(cfg => {
277
+ cfg.selectedTransactionFields.forEach(field => {
278
+ selectedTxFields.add(field);
279
+ });
280
+ });
281
+ let needsTokenBalances = selectedTxFields.has("tokenBalances");
282
+ let fields = [
283
+ "slot",
284
+ "transaction_index"
285
+ ];
286
+ Array.from(selectedTxFields).forEach(field => {
287
+ let queryField = toQueryTxField(field);
288
+ if (queryField !== undefined) {
289
+ fields.push(queryField);
290
+ return;
291
+ }
292
+ });
293
+ let needsTransactions = Array.from(selectedTxFields).some(field => {
294
+ switch (field) {
295
+ case "transactionIndex" :
296
+ case "tokenBalances" :
297
+ return false;
298
+ default:
299
+ return true;
300
+ }
301
+ });
302
+ let fields$1 = [
303
+ "slot",
304
+ "blockhash",
305
+ "block_time"
306
+ ];
307
+ let selected = new Set();
308
+ eventConfigs.forEach(cfg => {
309
+ cfg.selectedBlockFields.forEach(field => {
310
+ selected.add(field);
311
+ });
312
+ });
313
+ selected.forEach(field => {
314
+ let queryField = toQueryBlockField(field);
315
+ if (queryField !== undefined) {
316
+ fields$1.push(queryField);
317
+ return;
318
+ }
319
+ });
320
+ let getItemsOrThrow = async (fromBlock, toBlock, param, contractNameByAddress, knownHeight, param$1, param$2, itemsTarget, retry, logger) => {
321
+ let totalTimeRef = Performance.now();
322
+ let pageFetchRef = Performance.now();
268
323
  let instructionSelections = buildInstructionSelections(eventConfigs);
269
- let fields_block = [
270
- "slot",
271
- "blockhash",
272
- "block_time"
273
- ];
274
- let fields_transaction = needsTransactions ? [
275
- "slot",
276
- "transaction_index",
277
- "signatures",
278
- "fee_payer",
279
- "success",
280
- "err",
281
- "fee",
282
- "compute_units_consumed",
283
- "account_keys",
284
- "recent_blockhash",
285
- "version"
286
- ] : undefined;
324
+ let fields_block = fields$1;
325
+ let fields_transaction = needsTransactions ? fields : undefined;
287
326
  let fields_log = needsLogs ? [
288
327
  "slot",
289
328
  "transaction_index",
@@ -300,7 +339,7 @@ function make(param) {
300
339
  "pre_amount",
301
340
  "post_amount"
302
341
  ] : undefined;
303
- let fields = {
342
+ let fields$2 = {
304
343
  block: fields_block,
305
344
  transaction: fields_transaction,
306
345
  log: fields_log,
@@ -308,17 +347,18 @@ function make(param) {
308
347
  };
309
348
  let query_toSlot = Stdlib_Option.map(toBlock, toBlock => toBlock + 1 | 0);
310
349
  let query_instructions = instructionSelections;
311
- let query_fields = fields;
350
+ let query_fields = fields$2;
351
+ let query_maxNumInstructions = itemsTarget;
312
352
  let query = {
313
353
  fromSlot: fromBlock,
314
354
  toSlot: query_toSlot,
315
355
  instructions: query_instructions,
316
- fields: query_fields
356
+ fields: query_fields,
357
+ maxNumInstructions: query_maxNumInstructions
317
358
  };
318
- Prometheus.SourceRequestCount.increment(name, chain, "getInstructions");
319
- let resp;
359
+ let match;
320
360
  try {
321
- resp = await client.get(query);
361
+ match = await client.get(query);
322
362
  } catch (raw_exn) {
323
363
  let exn = Primitive_exceptions.internalToException(raw_exn);
324
364
  throw {
@@ -336,8 +376,13 @@ function make(param) {
336
376
  Error: new Error()
337
377
  };
338
378
  }
339
- let pageFetchTime = Hrtime.toSecondsFloat(Hrtime.timeSince(pageFetchRef));
340
- let parsingRef = Hrtime.makeTimer();
379
+ let resp = match[0];
380
+ let pageFetchTime = Performance.secondsSince(pageFetchRef);
381
+ let requestStats = [{
382
+ method: "getInstructions",
383
+ seconds: pageFetchTime
384
+ }];
385
+ let parsingRef = Performance.now();
341
386
  let blockTimeBySlot = {};
342
387
  resp.data.blocks.forEach(b => {
343
388
  let t = b.blockTime;
@@ -346,11 +391,6 @@ function make(param) {
346
391
  return;
347
392
  }
348
393
  });
349
- let txByKey = {};
350
- resp.data.transactions.forEach(tx => {
351
- let key = tx.slot.toString() + ":" + tx.transactionIndex.toString();
352
- txByKey[key] = tx;
353
- });
354
394
  let logsByKey = {};
355
395
  resp.data.logs.forEach(log => {
356
396
  let match = log.transactionIndex;
@@ -369,73 +409,45 @@ function make(param) {
369
409
  logsByKey[key] = [log];
370
410
  }
371
411
  });
372
- let tokenBalancesByTx = {};
373
- if (needsTokenBalances) {
374
- resp.data.tokenBalances.forEach(tb => {
375
- let txIdx = tb.transactionIndex;
376
- if (txIdx === undefined) {
377
- return;
378
- }
379
- let key = tb.slot.toString() + ":" + txIdx.toString();
380
- let existing = tokenBalancesByTx[key];
381
- if (existing !== undefined) {
382
- existing.push(tb);
383
- } else {
384
- tokenBalancesByTx[key] = [tb];
385
- }
386
- });
387
- }
388
412
  let parsedQueueItems = [];
389
413
  resp.data.instructions.forEach(instr => {
390
414
  let programId = instr.programId;
391
415
  let byteLengths = Stdlib_Option.getOr(orderingByProgram[instr.programId], []);
392
416
  let contractAddress = instr.programId;
393
- let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress, indexingAddresses);
417
+ let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress, contractNameByAddress);
394
418
  if (maybeConfig !== undefined) {
395
- let txKey = instr.slot.toString() + ":" + instr.transactionIndex.toString();
396
- let maybeTx = Stdlib_Option.map(txByKey[txKey], toSvmTransaction);
397
- let maybeTx$1 = maybeConfig.includeTokenBalances ? Stdlib_Option.map(maybeTx, tx => {
398
- let maybeBalances = Stdlib_Option.map(tokenBalancesByTx[txKey], bals => bals.map(toSvmTokenBalance));
399
- let newrecord = {...tx};
400
- newrecord.tokenBalances = maybeBalances;
401
- return newrecord;
402
- }) : maybeTx;
419
+ let eventConfig = maybeConfig.eventConfig;
403
420
  let logKey = instr.slot.toString() + ":" + instr.transactionIndex.toString() + ":" + serializeInstructionAddress(instr.instructionAddress);
404
421
  let maybeLogs = Stdlib_Option.map(logsByKey[logKey], logs => logs.map(log => ({
405
422
  kind: Stdlib_Option.getOr(log.kind, ""),
406
423
  message: Stdlib_Option.getOr(log.message, "")
407
424
  })));
408
- let slotKey = instr.slot.toString();
409
- let blockTime = blockTimeBySlot[slotKey];
410
- let payload = toSvmInstruction(instr, maybeConfig.contractName, maybeConfig.name, maybeConfig.includeTransaction ? maybeTx$1 : undefined, maybeConfig.includeLogs ? maybeLogs : undefined, {
411
- slot: instr.slot,
412
- time: Stdlib_Option.getOr(blockTime, 0),
413
- hash: ""
414
- });
425
+ let payload = toSvmInstruction(instr, eventConfig.contractName, eventConfig.name, eventConfig.includeLogs ? maybeLogs : undefined);
415
426
  parsedQueueItems.push({
416
427
  kind: 0,
417
- eventConfig: maybeConfig,
418
- timestamp: Stdlib_Option.getOr(blockTime, 0),
428
+ onEventRegistration: maybeConfig,
419
429
  chain: chain,
420
430
  blockNumber: instr.slot,
421
- blockHash: "",
422
431
  logIndex: synthLogIndex(instr),
432
+ transactionIndex: instr.transactionIndex,
423
433
  payload: payload
424
434
  });
425
435
  }
426
436
  });
427
- let parsingTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(parsingRef));
437
+ let parsingTimeElapsed = Performance.secondsSince(parsingRef);
428
438
  let highestSlot = resp.nextSlot - 1 | 0;
429
439
  let latestBlockTime = Stdlib_Option.getOr(blockTimeBySlot[highestSlot.toString()], 0);
430
440
  let blockHashes = resp.data.blocks.map(b => ({
431
441
  blockHash: b.blockhash,
432
442
  blockNumber: b.slot
433
443
  }));
434
- let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(totalTimeRef));
444
+ let totalTimeElapsed = Performance.secondsSince(totalTimeRef);
435
445
  return {
436
446
  knownHeight: knownHeight,
437
447
  blockHashes: blockHashes,
438
448
  parsedQueueItems: parsedQueueItems,
449
+ transactionStore: Primitive_option.some(match[1]),
450
+ blockStore: Primitive_option.some(match[2]),
439
451
  fromBlockQueried: fromBlock,
440
452
  latestFetchedBlockNumber: highestSlot,
441
453
  latestFetchedBlockTimestamp: latestBlockTime,
@@ -443,11 +455,13 @@ function make(param) {
443
455
  "total time elapsed (s)": totalTimeElapsed,
444
456
  "parsing time (s)": parsingTimeElapsed,
445
457
  "page fetch time (s)": pageFetchTime
446
- }
458
+ },
459
+ requestStats: requestStats
447
460
  };
448
461
  };
449
462
  let queryBlockDataRange = async (fromSlot, toSlot) => {
450
463
  let blockDatas = [];
464
+ let requestStats = [];
451
465
  let fromRef = fromSlot;
452
466
  let keepGoing = true;
453
467
  while (keepGoing) {
@@ -468,8 +482,13 @@ function make(param) {
468
482
  fields: query_fields,
469
483
  maxNumBlocks: query_maxNumBlocks
470
484
  };
471
- Prometheus.SourceRequestCount.increment(name, chain, "getBlockHashes");
472
- let resp = await client.get(query);
485
+ let timerRef = Performance.now();
486
+ let match = await client.get(query);
487
+ let resp = match[0];
488
+ requestStats.push({
489
+ method: "getBlockHashes",
490
+ seconds: Performance.secondsSince(timerRef)
491
+ });
473
492
  resp.data.blocks.forEach(b => {
474
493
  blockDatas.push({
475
494
  blockHash: b.blockhash,
@@ -483,14 +502,20 @@ function make(param) {
483
502
  fromRef = resp.nextSlot;
484
503
  }
485
504
  };
486
- return blockDatas;
505
+ return [
506
+ blockDatas,
507
+ requestStats
508
+ ];
487
509
  };
488
510
  let getBlockHashes = async (blockNumbers, param) => {
489
511
  let firstSlot = blockNumbers[0];
490
512
  if (firstSlot === undefined) {
491
513
  return {
492
- TAG: "Ok",
493
- _0: []
514
+ result: {
515
+ TAG: "Ok",
516
+ _0: []
517
+ },
518
+ requestStats: []
494
519
  };
495
520
  }
496
521
  try {
@@ -510,33 +535,43 @@ function make(param) {
510
535
  }
511
536
  requested.add(slot);
512
537
  });
513
- let blockDatas = await queryBlockDataRange(minSlot.contents, maxSlot.contents);
538
+ let match = await queryBlockDataRange(minSlot.contents, maxSlot.contents);
514
539
  return {
515
- TAG: "Ok",
516
- _0: blockDatas.filter(data => requested.delete(data.blockNumber))
540
+ result: {
541
+ TAG: "Ok",
542
+ _0: match[0].filter(data => requested.delete(data.blockNumber))
543
+ },
544
+ requestStats: match[1]
517
545
  };
518
546
  } catch (raw_exn) {
519
547
  let exn = Primitive_exceptions.internalToException(raw_exn);
520
548
  return {
521
- TAG: "Error",
522
- _0: exn
549
+ result: {
550
+ TAG: "Error",
551
+ _0: exn
552
+ },
553
+ requestStats: []
523
554
  };
524
555
  }
525
556
  };
526
557
  return {
527
- name: name,
558
+ name: "SvmHyperSync",
528
559
  sourceFor: "Sync",
529
560
  chain: chain,
530
561
  poweredByHyperSync: true,
531
562
  pollingInterval: 1000,
532
563
  getBlockHashes: getBlockHashes,
533
564
  getHeightOrThrow: async () => {
534
- let timer = Hrtime.makeTimer();
535
- let h = await client.getHeight();
536
- let seconds = Hrtime.toSecondsFloat(Hrtime.timeSince(timer));
537
- Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
538
- Prometheus.SourceRequestCount.addSeconds(name, chain, "getHeight", seconds);
539
- return h;
565
+ let timer = Performance.now();
566
+ let height = await client.getHeight();
567
+ let seconds = Performance.secondsSince(timer);
568
+ return {
569
+ height: height,
570
+ requestStats: [{
571
+ method: "getHeight",
572
+ seconds: seconds
573
+ }]
574
+ };
540
575
  },
541
576
  getItemsOrThrow: getItemsOrThrow
542
577
  };
@@ -549,9 +584,9 @@ export {
549
584
  buildProgramSchemas,
550
585
  parseDecoded,
551
586
  toSvmInstruction,
552
- toSvmTransaction,
553
- toSvmTokenBalance,
554
587
  probeRouter,
588
+ toQueryTxField,
589
+ toQueryBlockField,
555
590
  make,
556
591
  }
557
- /* Prometheus Not a pure module */
592
+ /* EventRouter Not a pure module */
@@ -0,0 +1,49 @@
1
+ // Binding to the Rust `TransactionStore` napi class. Transactions are kept in
2
+ // Rust as raw structs (their large fields never enter JS until read) keyed by
3
+ // (blockNumber, transactionIndex). One store lives per chain on `ChainState`;
4
+ // each fetch response contributes a page that is merged in. At batch
5
+ // preparation the selected fields are materialised in bulk, off the JS thread,
6
+ // in columnar form and zipped into plain JS objects on the main thread.
7
+ type t
8
+
9
+ @send external newEvm: (Core.transactionStoreCtor, ~shouldChecksum: bool) => t = "newEvm"
10
+ @send external newSvm: Core.transactionStoreCtor => t = "newSvm"
11
+ @send external newFuel: Core.transactionStoreCtor => t = "newFuel"
12
+
13
+ // The store's ecosystem is fixed here, from the chain's config. EVM carries the
14
+ // chain's address-checksumming setting; SVM/Fuel need no extra data.
15
+ let make = (~ecosystem: Ecosystem.name, ~shouldChecksum: bool): t => {
16
+ let ctor = Core.getAddon().transactionStore
17
+ switch ecosystem {
18
+ | Evm => ctor->newEvm(~shouldChecksum)
19
+ | Svm => ctor->newSvm
20
+ | Fuel => ctor->newFuel
21
+ }
22
+ }
23
+
24
+ // One event's selected transaction fields → store selection bitmask, built from
25
+ // the ecosystem's ordered field-name array (the bit index is the field code
26
+ // shared with the Rust store, `EvmTxField`/`SvmTxField`).
27
+ let makeMaskFn = FieldMask.makeMaskFn
28
+ let orMask = FieldMask.orMask
29
+ let fieldCodes = FieldMask.fieldCodes
30
+
31
+ // Drain another store (a fetch-response page) into this one.
32
+ @send external merge: (t, t) => unit = "merge"
33
+
34
+ // Bulk-materialise transactions off the JS thread, one row per
35
+ // (blockNumbers[i], transactionIndices[i]) key, decoding only the fields set in
36
+ // that row's own masks[i]. Result is aligned with the input.
37
+ @send
38
+ external materialize: (
39
+ t,
40
+ ~blockNumbers: array<int>,
41
+ ~transactionIndices: array<int>,
42
+ ~masks: array<float>,
43
+ ) => promise<array<Internal.eventTransaction>> = "materialize"
44
+
45
+ // Drop transactions for blocks at or below the given block (already processed).
46
+ @send external prune: (t, int) => unit = "prune"
47
+
48
+ // Drop transactions for blocks above the given block (rolled back).
49
+ @send external rollback: (t, int) => unit = "rollback"
@@ -0,0 +1,30 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Core from "../Core.res.mjs";
4
+ import * as FieldMask from "./FieldMask.res.mjs";
5
+
6
+ function make(ecosystem, shouldChecksum) {
7
+ let ctor = Core.getAddon().TransactionStore;
8
+ switch (ecosystem) {
9
+ case "evm" :
10
+ return ctor.newEvm(shouldChecksum);
11
+ case "fuel" :
12
+ return ctor.newFuel();
13
+ case "svm" :
14
+ return ctor.newSvm();
15
+ }
16
+ }
17
+
18
+ let makeMaskFn = FieldMask.makeMaskFn;
19
+
20
+ let orMask = FieldMask.orMask;
21
+
22
+ let fieldCodes = FieldMask.fieldCodes;
23
+
24
+ export {
25
+ make,
26
+ makeMaskFn,
27
+ orMask,
28
+ fieldCodes,
29
+ }
30
+ /* Core Not a pure module */
package/src/tui/Tui.res CHANGED
@@ -157,18 +157,15 @@ module App = {
157
157
  ->IndexerState.chainStates
158
158
  ->Dict.valuesToArray
159
159
  ->Array.map(cs => {
160
- let numEventsProcessed = cs->ChainState.numEventsProcessed
161
- let fetchState = cs->ChainState.fetchState
160
+ let data = cs->ChainState.toChainData
161
+ let numEventsProcessed = data.numEventsProcessed
162
162
  let committedProgressBlockNumber = cs->ChainState.committedProgressBlockNumber
163
- let timestampCaughtUpToHeadOrEndblock = cs->ChainState.timestampCaughtUpToHeadOrEndblock
163
+ let timestampCaughtUpToHeadOrEndblock = data.timestampCaughtUpToHeadOrEndblock
164
164
  let sourceManager = cs->ChainState.sourceManager
165
- let latestFetchedBlockNumber = Pervasives.max(fetchState->FetchState.bufferBlockNumber, 0)
165
+ let latestFetchedBlockNumber = data.latestFetchedBlockNumber
166
166
  let hasProcessedToEndblock = cs->ChainState.hasProcessedToEndblock
167
- let knownHeight = hasProcessedToEndblock
168
- ? fetchState.endBlock->Option.getOr(fetchState.knownHeight)
169
- : fetchState.knownHeight
170
167
 
171
- let firstEventBlock = fetchState.firstEventBlock
168
+ let firstEventBlock = data.firstEventBlockNumber
172
169
  let progress: TuiData.progress = if hasProcessedToEndblock {
173
170
  // If the endblock has been reached then set the progress to synced.
174
171
  // if there's chains that have no events in the block range start->end,
@@ -204,19 +201,19 @@ module App = {
204
201
  (
205
202
  {
206
203
  progress,
207
- knownHeight,
204
+ knownHeight: data.knownHeight,
208
205
  latestFetchedBlockNumber,
209
206
  eventsProcessed: numEventsProcessed,
210
207
  chainId: (cs->ChainState.chainConfig).id->Int.toString,
211
- progressBlock: committedProgressBlockNumber < fetchState.startBlock
212
- ? Some(fetchState.startBlock)
208
+ progressBlock: committedProgressBlockNumber < data.startBlock
209
+ ? Some(data.startBlock)
213
210
  : Some(committedProgressBlockNumber),
214
211
  bufferBlock: Some(latestFetchedBlockNumber),
215
- sourceBlock: Some(fetchState.knownHeight),
216
- firstEventBlockNumber: fetchState.firstEventBlock,
217
- startBlock: fetchState.startBlock,
218
- endBlock: fetchState.endBlock,
219
- poweredByHyperSync: (sourceManager->SourceManager.getActiveSource).poweredByHyperSync,
212
+ sourceBlock: Some(cs->ChainState.knownHeight),
213
+ firstEventBlockNumber: firstEventBlock,
214
+ startBlock: data.startBlock,
215
+ endBlock: data.endBlock,
216
+ poweredByHyperSync: data.poweredByHyperSync,
220
217
  blockUnit: switch (state->IndexerState.config).ecosystem.name {
221
218
  | Svm => "Slot"
222
219
  | Evm | Fuel => "Block"
@@ -8,7 +8,6 @@ import * as SyncETA from "./components/SyncETA.res.mjs";
8
8
  import * as TuiData from "./components/TuiData.res.mjs";
9
9
  import * as Messages from "./components/Messages.res.mjs";
10
10
  import * as ChainState from "../ChainState.res.mjs";
11
- import * as FetchState from "../FetchState.res.mjs";
12
11
  import * as IndexerState from "../IndexerState.res.mjs";
13
12
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
14
13
  import InkBigText from "ink-big-text";
@@ -208,15 +207,14 @@ function Tui$App(props) {
208
207
  };
209
208
  }, [getState]);
210
209
  let chains = Object.values(IndexerState.chainStates(state)).map(cs => {
211
- let numEventsProcessed = ChainState.numEventsProcessed(cs);
212
- let fetchState = ChainState.fetchState(cs);
210
+ let data = ChainState.toChainData(cs);
211
+ let numEventsProcessed = data.numEventsProcessed;
213
212
  let committedProgressBlockNumber = ChainState.committedProgressBlockNumber(cs);
214
- let timestampCaughtUpToHeadOrEndblock = ChainState.timestampCaughtUpToHeadOrEndblock(cs);
213
+ let timestampCaughtUpToHeadOrEndblock = data.timestampCaughtUpToHeadOrEndblock;
215
214
  let sourceManager = ChainState.sourceManager(cs);
216
- let latestFetchedBlockNumber = Primitive_int.max(FetchState.bufferBlockNumber(fetchState), 0);
215
+ let latestFetchedBlockNumber = data.latestFetchedBlockNumber;
217
216
  let hasProcessedToEndblock = ChainState.hasProcessedToEndblock(cs);
218
- let knownHeight = hasProcessedToEndblock ? Stdlib_Option.getOr(fetchState.endBlock, fetchState.knownHeight) : fetchState.knownHeight;
219
- let firstEventBlock = fetchState.firstEventBlock;
217
+ let firstEventBlock = data.firstEventBlockNumber;
220
218
  let progress = hasProcessedToEndblock ? ({
221
219
  TAG: "Synced",
222
220
  _0: {
@@ -259,16 +257,16 @@ function Tui$App(props) {
259
257
  return {
260
258
  chainId: ChainState.chainConfig(cs).id.toString(),
261
259
  eventsProcessed: numEventsProcessed,
262
- progressBlock: committedProgressBlockNumber < fetchState.startBlock ? fetchState.startBlock : committedProgressBlockNumber,
260
+ progressBlock: committedProgressBlockNumber < data.startBlock ? data.startBlock : committedProgressBlockNumber,
263
261
  bufferBlock: latestFetchedBlockNumber,
264
- sourceBlock: fetchState.knownHeight,
265
- startBlock: fetchState.startBlock,
266
- endBlock: fetchState.endBlock,
267
- firstEventBlockNumber: fetchState.firstEventBlock,
268
- poweredByHyperSync: SourceManager.getActiveSource(sourceManager).poweredByHyperSync,
262
+ sourceBlock: ChainState.knownHeight(cs),
263
+ startBlock: data.startBlock,
264
+ endBlock: data.endBlock,
265
+ firstEventBlockNumber: firstEventBlock,
266
+ poweredByHyperSync: data.poweredByHyperSync,
269
267
  progress: progress,
270
268
  latestFetchedBlockNumber: latestFetchedBlockNumber,
271
- knownHeight: knownHeight,
269
+ knownHeight: data.currentBlockHeight,
272
270
  blockUnit: tmp,
273
271
  rateLimitTimeMs: SourceManager.getRateLimitTimeMs(sourceManager),
274
272
  isRateLimited: SourceManager.isRateLimited(sourceManager),