envio 3.3.0-alpha.3 → 3.3.0-alpha.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.3.0-alpha.3",
3
+ "version": "3.3.0-alpha.4",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -69,10 +69,10 @@
69
69
  "tsx": "4.21.0"
70
70
  },
71
71
  "optionalDependencies": {
72
- "envio-linux-x64": "3.3.0-alpha.3",
73
- "envio-linux-x64-musl": "3.3.0-alpha.3",
74
- "envio-linux-arm64": "3.3.0-alpha.3",
75
- "envio-darwin-x64": "3.3.0-alpha.3",
76
- "envio-darwin-arm64": "3.3.0-alpha.3"
72
+ "envio-linux-x64": "3.3.0-alpha.4",
73
+ "envio-linux-x64-musl": "3.3.0-alpha.4",
74
+ "envio-linux-arm64": "3.3.0-alpha.4",
75
+ "envio-darwin-x64": "3.3.0-alpha.4",
76
+ "envio-darwin-arm64": "3.3.0-alpha.4"
77
77
  }
78
78
  }
package/src/Bin.res CHANGED
@@ -71,6 +71,9 @@ let run = async args => {
71
71
  }
72
72
  }
73
73
  } catch {
74
+ | Main.FatalError(_) =>
75
+ // Already logged with full context by Main.start's onError; just exit.
76
+ NodeJs.process->NodeJs.exitWithCode(Failure)
74
77
  | exn =>
75
78
  // Log just the exception's own message — wrapping it in "Failed at
76
79
  // initialization" and pino's err serializer buries the real cause under
package/src/Bin.res.mjs CHANGED
@@ -79,6 +79,10 @@ async function run(args) {
79
79
  }
80
80
  } catch (raw_exn) {
81
81
  let exn = Primitive_exceptions.internalToException(raw_exn);
82
+ if (exn.RE_EXN_ID === Main.FatalError) {
83
+ Process.exit(1);
84
+ return;
85
+ }
82
86
  let e = Primitive_exceptions.internalToException(exn);
83
87
  let message = e.RE_EXN_ID === "JsExn" ? Stdlib_Option.getOr(Stdlib_JsExn.message(e._1), "Failed at initialization") : "Failed at initialization";
84
88
  Logging.error(message);
@@ -11,13 +11,12 @@ type partitionQueryResponse = {
11
11
  let runContractRegistersOrThrow = async (
12
12
  ~itemsWithContractRegister: array<Internal.item>,
13
13
  ~config: Config.t,
14
- ~chainState: ChainState.t,
15
14
  ~page: option<TransactionStore.t>,
16
15
  ) => {
17
16
  // contractRegister handlers can read event.transaction, so materialise the
18
17
  // selected fields onto the payloads before running them. All items belong to
19
18
  // the chain being fetched, hence its single page store and mask.
20
- await chainState->ChainState.materializePageItems(~items=itemsWithContractRegister, ~page)
19
+ await ChainState.materializePageItems(~items=itemsWithContractRegister, ~page)
21
20
 
22
21
  let itemsWithDcs = []
23
22
 
@@ -233,7 +232,6 @@ let rec onQueryResponse = async (
233
232
  switch await runContractRegistersOrThrow(
234
233
  ~itemsWithContractRegister,
235
234
  ~config=state->IndexerState.config,
236
- ~chainState,
237
235
  ~page=transactionStore,
238
236
  ) {
239
237
  | exception exn => IndexerState.errorExit(state, exn->ErrorHandling.make)
@@ -16,8 +16,8 @@ import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
16
16
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
17
17
  import * as ContractRegisterContext from "./ContractRegisterContext.res.mjs";
18
18
 
19
- async function runContractRegistersOrThrow(itemsWithContractRegister, config, chainState, page) {
20
- await ChainState.materializePageItems(chainState, itemsWithContractRegister, page);
19
+ async function runContractRegistersOrThrow(itemsWithContractRegister, config, page) {
20
+ await ChainState.materializePageItems(itemsWithContractRegister, page);
21
21
  let itemsWithDcs = [];
22
22
  let onRegister = (item, contractAddress, contractName) => {
23
23
  let dc_registrationBlock = item.blockNumber;
@@ -145,7 +145,7 @@ async function onQueryResponse(state, param, stateId, scheduleFetch, schedulePro
145
145
  }
146
146
  let newItemsWithDcs;
147
147
  try {
148
- newItemsWithDcs = await runContractRegistersOrThrow(itemsWithContractRegister, IndexerState.config(state), chainState, transactionStore);
148
+ newItemsWithDcs = await runContractRegistersOrThrow(itemsWithContractRegister, IndexerState.config(state), transactionStore);
149
149
  } catch (raw_exn) {
150
150
  let exn = Primitive_exceptions.internalToException(raw_exn);
151
151
  return IndexerState.errorExit(state, ErrorHandling.make(exn, undefined, undefined));
@@ -21,8 +21,6 @@ type t = {
21
21
  // transactionIndex). Fetch responses merge their page in; entries are pruned
22
22
  // as the chain progresses and dropped above the target on rollback.
23
23
  transactionStore: TransactionStore.t,
24
- // Bitmask of the transaction fields the store materialises at batch prep.
25
- transactionFieldMask: float,
26
24
  }
27
25
 
28
26
  // Per-chain shape returned by the status API.
@@ -67,7 +65,6 @@ let make = (
67
65
  ~numEventsProcessed=0.,
68
66
  ~timestampCaughtUpToHeadOrEndblock=None,
69
67
  ~isProgressAtHead=false,
70
- ~transactionFieldMask=0.,
71
68
  ~logger: Pino.t,
72
69
  ): t => {
73
70
  logger,
@@ -82,7 +79,6 @@ let make = (
82
79
  reorgDetection,
83
80
  safeCheckpointTracking,
84
81
  transactionStore: TransactionStore.make(),
85
- transactionFieldMask,
86
82
  }
87
83
 
88
84
  let makeInternal = (
@@ -328,7 +324,6 @@ let makeInternal = (
328
324
  ~committedProgressBlockNumber=progressBlockNumber,
329
325
  ~timestampCaughtUpToHeadOrEndblock,
330
326
  ~numEventsProcessed,
331
- ~transactionFieldMask=config.ecosystem.transactionFieldMask(eventConfigs),
332
327
  ~logger,
333
328
  )
334
329
  }
@@ -503,18 +498,14 @@ let isAtHeadWithoutEndBlock = (cs: t) =>
503
498
  // Materialise the chain store's selected transaction fields onto a batch's
504
499
  // items at batch prep (the persistent-store path).
505
500
  let materializeBatchItems = (cs: t, ~items: array<Internal.item>) =>
506
- cs.transactionStore->TransactionStore.materializeItems(~items, ~mask=cs.transactionFieldMask)
501
+ cs.transactionStore->TransactionStore.materializeItems(~items)
507
502
 
508
503
  // Materialise a fetch-response page's transactions onto its items before
509
504
  // contract-register handlers read them. `None` pages (RPC/Fuel/Simulate keep the
510
505
  // transaction inline) are a no-op.
511
- let materializePageItems = (
512
- cs: t,
513
- ~items: array<Internal.item>,
514
- ~page: option<TransactionStore.t>,
515
- ) =>
506
+ let materializePageItems = (~items: array<Internal.item>, ~page: option<TransactionStore.t>) =>
516
507
  switch page {
517
- | Some(store) => store->TransactionStore.materializeItems(~items, ~mask=cs.transactionFieldMask)
508
+ | Some(store) => store->TransactionStore.materializeItems(~items)
518
509
  | None => Promise.resolve()
519
510
  }
520
511
 
@@ -38,12 +38,11 @@ function configAddresses(chainConfig) {
38
38
  return addresses;
39
39
  }
40
40
 
41
- function make(chainConfig, fetchState, sourceManager, reorgDetection, committedProgressBlockNumber, safeCheckpointTrackingOpt, numEventsProcessedOpt, timestampCaughtUpToHeadOrEndblockOpt, isProgressAtHeadOpt, transactionFieldMaskOpt, logger) {
41
+ function make(chainConfig, fetchState, sourceManager, reorgDetection, committedProgressBlockNumber, safeCheckpointTrackingOpt, numEventsProcessedOpt, timestampCaughtUpToHeadOrEndblockOpt, isProgressAtHeadOpt, logger) {
42
42
  let safeCheckpointTracking = safeCheckpointTrackingOpt !== undefined ? Primitive_option.valFromOption(safeCheckpointTrackingOpt) : undefined;
43
43
  let numEventsProcessed = numEventsProcessedOpt !== undefined ? numEventsProcessedOpt : 0;
44
44
  let timestampCaughtUpToHeadOrEndblock = timestampCaughtUpToHeadOrEndblockOpt !== undefined ? Primitive_option.valFromOption(timestampCaughtUpToHeadOrEndblockOpt) : undefined;
45
45
  let isProgressAtHead = isProgressAtHeadOpt !== undefined ? isProgressAtHeadOpt : false;
46
- let transactionFieldMask = transactionFieldMaskOpt !== undefined ? transactionFieldMaskOpt : 0;
47
46
  return {
48
47
  logger: logger,
49
48
  fetchState: fetchState,
@@ -56,8 +55,7 @@ function make(chainConfig, fetchState, sourceManager, reorgDetection, committedP
56
55
  pendingBudget: 0,
57
56
  reorgDetection: reorgDetection,
58
57
  safeCheckpointTracking: safeCheckpointTracking,
59
- transactionStore: TransactionStore.make(),
60
- transactionFieldMask: transactionFieldMask
58
+ transactionStore: TransactionStore.make()
61
59
  };
62
60
  }
63
61
 
@@ -176,7 +174,7 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
176
174
  sources$1 = sources._0;
177
175
  break;
178
176
  }
179
- return make(chainConfig, fetchState, SourceManager.make(sources$1, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), ReorgDetection.make(chainReorgCheckpoints, maxReorgDepth, config.shouldRollbackOnReorg), progressBlockNumber, Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, config.ecosystem.transactionFieldMask(eventConfigs), logger);
177
+ return make(chainConfig, fetchState, SourceManager.make(sources$1, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), ReorgDetection.make(chainReorgCheckpoints, maxReorgDepth, config.shouldRollbackOnReorg), progressBlockNumber, Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, logger);
180
178
  }
181
179
 
182
180
  function makeFromConfig(chainConfig, config, registrations, knownHeight) {
@@ -326,12 +324,12 @@ function isAtHeadWithoutEndBlock(cs) {
326
324
  }
327
325
 
328
326
  function materializeBatchItems(cs, items) {
329
- return TransactionStore.materializeItems(cs.transactionStore, items, cs.transactionFieldMask);
327
+ return TransactionStore.materializeItems(cs.transactionStore, items);
330
328
  }
331
329
 
332
- function materializePageItems(cs, items, page) {
330
+ function materializePageItems(items, page) {
333
331
  if (page !== undefined) {
334
- return TransactionStore.materializeItems(Primitive_option.valFromOption(page), items, cs.transactionFieldMask);
332
+ return TransactionStore.materializeItems(Primitive_option.valFromOption(page), items);
335
333
  } else {
336
334
  return Promise.resolve();
337
335
  }
@@ -15,7 +15,6 @@ let make: (
15
15
  ~numEventsProcessed: float=?,
16
16
  ~timestampCaughtUpToHeadOrEndblock: option<Date.t>=?,
17
17
  ~isProgressAtHead: bool=?,
18
- ~transactionFieldMask: float=?,
19
18
  ~logger: Pino.t,
20
19
  ) => t
21
20
 
@@ -112,7 +111,6 @@ let handleQueryResult: (
112
111
  ) => unit
113
112
  let materializeBatchItems: (t, ~items: array<Internal.item>) => promise<unit>
114
113
  let materializePageItems: (
115
- t,
116
114
  ~items: array<Internal.item>,
117
115
  ~page: option<TransactionStore.t>,
118
116
  ) => promise<unit>
package/src/Ecosystem.res CHANGED
@@ -34,10 +34,6 @@ type t = {
34
34
  registration from an item's opaque payload. `event.transaction` is written
35
35
  onto the payload at batch prep (HyperSync) or inline (RPC/simulate). */
36
36
  toEvent: Internal.eventItem => Internal.event,
37
- /** Bitmask (as a float) of the transaction fields selected across the chain's
38
- events — the set the store materialises at batch prep. `0.` when the
39
- ecosystem carries transactions inline. */
40
- transactionFieldMask: array<Internal.eventConfig> => float,
41
37
  /** Build the per-item child logger for an event item, with
42
38
  ecosystem-specific log fields (EVM/Fuel: contract/event/address; SVM:
43
39
  program/instruction/programId). Closes over the injected logger. */
@@ -442,6 +442,7 @@ let buildEvmEventConfig = (
442
442
  startBlock: resolvedStartBlock,
443
443
  selectedBlockFields,
444
444
  selectedTransactionFields,
445
+ transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
445
446
  sighash,
446
447
  topicCount,
447
448
  paramsMetadata: params,
@@ -500,6 +501,7 @@ let buildSvmInstructionEventConfig = (
500
501
  discriminatorByteLen,
501
502
  includeLogs,
502
503
  selectedTransactionFields,
504
+ transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
503
505
  accountFilters,
504
506
  isInner,
505
507
  accounts,
@@ -568,6 +570,7 @@ let buildFuelEventConfig = (
568
570
  startBlock,
569
571
  // Fuel keeps the transaction inline on the payload; nothing to materialise.
570
572
  selectedTransactionFields: Utils.Set.make(),
573
+ transactionFieldMask: 0.,
571
574
  kind: fuelKind,
572
575
  }
573
576
  }
@@ -1,5 +1,7 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Evm from "./sources/Evm.res.mjs";
4
+ import * as Svm from "./sources/Svm.res.mjs";
3
5
  import * as Utils from "./Utils.res.mjs";
4
6
  import * as Address from "./Address.res.mjs";
5
7
  import * as FuelSDK from "./sources/FuelSDK.res.mjs";
@@ -294,6 +296,7 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
294
296
  let filterByAddresses = match.filterByAddresses;
295
297
  let resolvedStartBlock = whereStartBlock !== undefined ? whereStartBlock : startBlock;
296
298
  let match$1 = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
299
+ let selectedTransactionFields = match$1[1];
297
300
  return {
298
301
  id: sighash + "_" + topicCount.toString(),
299
302
  name: eventName,
@@ -307,7 +310,8 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
307
310
  paramsRawEventSchema: buildParamsSchema(params),
308
311
  simulateParamsSchema: buildSimulateParamsSchema(params),
309
312
  startBlock: resolvedStartBlock,
310
- selectedTransactionFields: match$1[1],
313
+ selectedTransactionFields: selectedTransactionFields,
314
+ transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
311
315
  getEventFiltersOrThrow: match.getEventFiltersOrThrow,
312
316
  selectedBlockFields: match$1[0],
313
317
  sighash: sighash,
@@ -337,6 +341,7 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
337
341
  simulateParamsSchema: paramsSchema,
338
342
  startBlock: startBlock,
339
343
  selectedTransactionFields: selectedTransactionFields,
344
+ transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
340
345
  programId: programId,
341
346
  discriminator: discriminator,
342
347
  discriminatorByteLen: discriminatorByteLen,
@@ -406,6 +411,7 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, is
406
411
  simulateParamsSchema: paramsSchema,
407
412
  startBlock: startBlock,
408
413
  selectedTransactionFields: new Set(),
414
+ transactionFieldMask: 0,
409
415
  kind: fuelKind
410
416
  };
411
417
  }
@@ -41,12 +41,6 @@ type partition = {
41
41
  latestFetchedBlock: blockNumberAndTimestamp,
42
42
  selection: selection,
43
43
  addressesByContractName: dict<array<Address.t>>,
44
- // Reverse index address→contractName, derived from addressesByContractName.
45
- // Used by EventRouter to resolve a log's owning contract from the partition
46
- // that fetched it (instead of a chain-wide snapshot). Always recomputed in
47
- // OptimizedPartitions.make, so partition literals can seed it with an empty
48
- // dict.
49
- contractNameByAddress: dict<string>,
50
44
  mergeBlock: option<int>,
51
45
  // When set, partition indexes a single dynamic contract type.
52
46
  // The addressesByContractName must contain only addresses for this contract.
@@ -82,16 +76,17 @@ type query = {
82
76
  mutable progress: float,
83
77
  selection: selection,
84
78
  addressesByContractName: dict<array<Address.t>>,
85
- // The owning partition's reverse index, referenced (not copied) so routing
86
- // resolves ownership without a chain-wide snapshot.
87
- contractNameByAddress: dict<string>,
88
79
  }
89
80
 
90
- // Invert addressesByContractName into address→contractName. 1:1 today (each
91
- // address belongs to one contract), so no key collisions.
92
- let deriveContractNameByAddress = (addressesByContractName: dict<array<Address.t>>): dict<
81
+ // Invert addressesByContractName into address→contractName for log-ownership
82
+ // routing. 1:1 today (each address belongs to one contract), so no key
83
+ // collisions. Memoized on the addressesByContractName object so a partition's
84
+ // many responses share one derivation and a large factory never rebuilds the
85
+ // whole index; sound because the dict is immutable after construction (every
86
+ // mutation produces a new dict).
87
+ let deriveContractNameByAddress: dict<array<Address.t>> => dict<
93
88
  string,
94
- > => {
89
+ > = Utils.WeakMap.memoize(addressesByContractName => {
95
90
  let result = Dict.make()
96
91
  addressesByContractName->Utils.Dict.forEachWithKey((addresses, contractName) => {
97
92
  for i in 0 to addresses->Array.length - 1 {
@@ -99,7 +94,7 @@ let deriveContractNameByAddress = (addressesByContractName: dict<array<Address.t
99
94
  }
100
95
  })
101
96
  result
102
- }
97
+ })
103
98
 
104
99
  // Default estimate for a query whose partition hasn't responded yet, so the
105
100
  // shared budget still accounts for unknown queries instead of treating them as
@@ -214,7 +209,6 @@ module OptimizedPartitions = {
214
209
  latestFetchedBlock: {blockNumber: potentialMergeBlock, blockTimestamp: 0},
215
210
  mergeBlock: None,
216
211
  addressesByContractName: Dict.make(), // set below
217
- contractNameByAddress: Dict.make(), // derived in make
218
212
  mutPendingQueries: [],
219
213
  prevQueryRange: minRange,
220
214
  prevPrevQueryRange: minRange,
@@ -397,12 +391,7 @@ module OptimizedPartitions = {
397
391
  for idx in 0 to partitionsCount - 1 {
398
392
  let p = newPartitions->Array.getUnsafe(idx)
399
393
  idsInAscOrder->Array.setUnsafe(idx, p.id)
400
- // Single point where every partition's reverse index is (re)derived, so all
401
- // construction paths (literals, spreads, merges, splits) stay consistent.
402
- entities->Dict.set(
403
- p.id,
404
- {...p, contractNameByAddress: deriveContractNameByAddress(p.addressesByContractName)},
405
- )
394
+ entities->Dict.set(p.id, p)
406
395
  }
407
396
 
408
397
  {
@@ -901,7 +890,6 @@ OptimizedPartitions.t => {
901
890
  selection: normalSelection,
902
891
  dynamicContract: isDynamic ? Some(contractName) : None,
903
892
  addressesByContractName,
904
- contractNameByAddress: Dict.make(), // derived in make
905
893
  mergeBlock: None,
906
894
  mutPendingQueries: [],
907
895
  prevQueryRange: 0,
@@ -1244,7 +1232,6 @@ let registerDynamicContracts = (
1244
1232
  selection: fetchState.normalSelection,
1245
1233
  dynamicContract: Some(contractName),
1246
1234
  addressesByContractName,
1247
- contractNameByAddress: Dict.make(), // derived in make
1248
1235
  mergeBlock: None,
1249
1236
  mutPendingQueries: p.mutPendingQueries,
1250
1237
  prevQueryRange: p.prevQueryRange,
@@ -1396,7 +1383,6 @@ let pushQueriesForRange = (
1396
1383
  chainId: 0,
1397
1384
  progress: 0.,
1398
1385
  addressesByContractName,
1399
- contractNameByAddress: partition.contractNameByAddress,
1400
1386
  })
1401
1387
  | Some(chunkRange) =>
1402
1388
  let maxBlock = switch rangeEndBlock {
@@ -1426,7 +1412,6 @@ let pushQueriesForRange = (
1426
1412
  chainId: 0,
1427
1413
  progress: 0.,
1428
1414
  addressesByContractName,
1429
- contractNameByAddress: partition.contractNameByAddress,
1430
1415
  })
1431
1416
  chunkFromBlock := chunkToBlock + 1
1432
1417
  chunkIdx := chunkIdx.contents + 1
@@ -1448,7 +1433,6 @@ let pushQueriesForRange = (
1448
1433
  chainId: 0,
1449
1434
  progress: 0.,
1450
1435
  addressesByContractName,
1451
- contractNameByAddress: partition.contractNameByAddress,
1452
1436
  })
1453
1437
  }
1454
1438
  }
@@ -1703,7 +1687,6 @@ let make = (
1703
1687
  eventConfigs: notDependingOnAddresses,
1704
1688
  },
1705
1689
  addressesByContractName: Dict.make(),
1706
- contractNameByAddress: Dict.make(), // derived in make
1707
1690
  mergeBlock: None,
1708
1691
  dynamicContract: None,
1709
1692
  mutPendingQueries: [],