envio 3.3.0-alpha.1 → 3.3.0-alpha.3

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 (84) hide show
  1. package/index.d.ts +23 -21
  2. package/package.json +6 -6
  3. package/src/Batch.res +0 -6
  4. package/src/Batch.res.mjs +0 -11
  5. package/src/BatchProcessing.res +2 -12
  6. package/src/BatchProcessing.res.mjs +2 -7
  7. package/src/ChainFetching.res +42 -6
  8. package/src/ChainFetching.res.mjs +30 -11
  9. package/src/ChainMetadata.res +1 -11
  10. package/src/ChainMetadata.res.mjs +1 -10
  11. package/src/ChainState.res +150 -1
  12. package/src/ChainState.res.mjs +138 -9
  13. package/src/ChainState.resi +51 -1
  14. package/src/Config.res +3 -6
  15. package/src/Config.res.mjs +2 -3
  16. package/src/Core.res +7 -0
  17. package/src/CrossChainState.res +24 -26
  18. package/src/CrossChainState.res.mjs +19 -16
  19. package/src/Ecosystem.res +6 -3
  20. package/src/Envio.res +3 -2
  21. package/src/EventConfigBuilder.res +61 -23
  22. package/src/EventConfigBuilder.res.mjs +27 -13
  23. package/src/EventProcessing.res +63 -21
  24. package/src/EventProcessing.res.mjs +47 -22
  25. package/src/FetchState.res +53 -43
  26. package/src/FetchState.res.mjs +71 -54
  27. package/src/HandlerLoader.res +10 -1
  28. package/src/HandlerLoader.res.mjs +15 -8
  29. package/src/Internal.res +46 -7
  30. package/src/Internal.res.mjs +19 -1
  31. package/src/LoadLayer.res +5 -5
  32. package/src/LoadLayer.res.mjs +6 -6
  33. package/src/Main.res +3 -50
  34. package/src/Main.res.mjs +2 -23
  35. package/src/PgStorage.res +4 -4
  36. package/src/PgStorage.res.mjs +5 -5
  37. package/src/Prometheus.res +10 -10
  38. package/src/Prometheus.res.mjs +9 -9
  39. package/src/PruneStaleHistory.res +2 -2
  40. package/src/PruneStaleHistory.res.mjs +3 -3
  41. package/src/Rollback.res +3 -3
  42. package/src/Rollback.res.mjs +4 -4
  43. package/src/SimulateItems.res +80 -15
  44. package/src/SimulateItems.res.mjs +65 -21
  45. package/src/TestIndexer.res +48 -36
  46. package/src/TestIndexer.res.mjs +35 -28
  47. package/src/bindings/Performance.res +7 -0
  48. package/src/bindings/Performance.res.mjs +21 -0
  49. package/src/bindings/Performance.resi +7 -0
  50. package/src/sources/EventRouter.res +17 -21
  51. package/src/sources/EventRouter.res.mjs +6 -9
  52. package/src/sources/Evm.res +47 -67
  53. package/src/sources/Evm.res.mjs +42 -65
  54. package/src/sources/Fuel.res +3 -3
  55. package/src/sources/Fuel.res.mjs +1 -6
  56. package/src/sources/HyperFuelSource.res +15 -11
  57. package/src/sources/HyperFuelSource.res.mjs +13 -11
  58. package/src/sources/HyperSync.res +7 -1
  59. package/src/sources/HyperSync.res.mjs +6 -3
  60. package/src/sources/HyperSync.resi +2 -0
  61. package/src/sources/HyperSyncClient.res +14 -79
  62. package/src/sources/HyperSyncClient.res.mjs +1 -22
  63. package/src/sources/HyperSyncSource.res +44 -27
  64. package/src/sources/HyperSyncSource.res.mjs +32 -27
  65. package/src/sources/RpcSource.res +14 -10
  66. package/src/sources/RpcSource.res.mjs +11 -9
  67. package/src/sources/SimulateSource.res +4 -2
  68. package/src/sources/SimulateSource.res.mjs +1 -0
  69. package/src/sources/Source.res +5 -1
  70. package/src/sources/SourceManager.res +17 -16
  71. package/src/sources/SourceManager.res.mjs +10 -15
  72. package/src/sources/Svm.res +23 -6
  73. package/src/sources/Svm.res.mjs +24 -6
  74. package/src/sources/SvmHyperSyncClient.res +3 -29
  75. package/src/sources/SvmHyperSyncSource.res +78 -96
  76. package/src/sources/SvmHyperSyncSource.res.mjs +79 -91
  77. package/src/sources/TransactionStore.res +128 -0
  78. package/src/sources/TransactionStore.res.mjs +97 -0
  79. package/src/tui/Tui.res +13 -16
  80. package/src/tui/Tui.res.mjs +12 -14
  81. package/svm.schema.json +30 -37
  82. package/src/bindings/Hrtime.res +0 -58
  83. package/src/bindings/Hrtime.res.mjs +0 -90
  84. package/src/bindings/Hrtime.resi +0 -30
@@ -135,6 +135,64 @@ function findEventConfig(config, contractName, eventName) {
135
135
  return found.contents;
136
136
  }
137
137
 
138
+ let dummySrcAddress = "0x0000000000000000000000000000000000000000";
139
+
140
+ function firstContractAddress(chainConfig, contractName) {
141
+ let found = {
142
+ contents: undefined
143
+ };
144
+ chainConfig.contracts.forEach(contract => {
145
+ if (Stdlib_Option.isNone(found.contents) && contract.name === contractName) {
146
+ found.contents = contract.addresses[0];
147
+ return;
148
+ }
149
+ });
150
+ return found.contents;
151
+ }
152
+
153
+ function deriveSrcAddress(providedSrcAddress, eventConfig, chainConfig) {
154
+ if (providedSrcAddress !== undefined) {
155
+ return Primitive_option.valFromOption(providedSrcAddress);
156
+ }
157
+ if (eventConfig.isWildcard) {
158
+ return dummySrcAddress;
159
+ }
160
+ let addr = firstContractAddress(chainConfig, eventConfig.contractName);
161
+ if (addr !== undefined) {
162
+ return Primitive_option.valFromOption(addr);
163
+ } else {
164
+ return dummySrcAddress;
165
+ }
166
+ }
167
+
168
+ function validateSrcAddresses(simulateItems, config, chainConfig, indexingAddresses) {
169
+ let known = new Set();
170
+ indexingAddresses.forEach(ia => {
171
+ known.add(ia.address);
172
+ });
173
+ simulateItems.forEach(rawJson => {
174
+ let match = rawJson.contract;
175
+ let match$1 = rawJson.event;
176
+ if (match === undefined) {
177
+ return;
178
+ }
179
+ if (match$1 === undefined) {
180
+ return;
181
+ }
182
+ let eventConfig = findEventConfig(config, match, match$1);
183
+ if (eventConfig === undefined) {
184
+ return;
185
+ }
186
+ if (eventConfig.isWildcard) {
187
+ return;
188
+ }
189
+ let srcAddress = deriveSrcAddress(rawJson.srcAddress, eventConfig, chainConfig);
190
+ if (!known.has(srcAddress)) {
191
+ return Stdlib_JsError.throwWithMessage(`simulate: ` + match + `.` + match$1 + ` resolved to address ` + srcAddress + `, which isn't indexed on chain ` + chainConfig.id.toString() + `. ` + (`Provide a "srcAddress" configured or registered for ` + match + ` on this chain, or use a wildcard event.`));
192
+ }
193
+ });
194
+ }
195
+
138
196
  function parse(simulateItems, config, chainConfig) {
139
197
  let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
140
198
  let chainId = chainConfig.id;
@@ -169,26 +227,7 @@ function parse(simulateItems, config, chainConfig) {
169
227
  currentLogIndex.contents = li$1 + 1 | 0;
170
228
  logIndex = li$1;
171
229
  }
172
- let addr = rawJson.srcAddress;
173
- let srcAddress;
174
- if (addr !== undefined) {
175
- srcAddress = Primitive_option.valFromOption(addr);
176
- } else {
177
- let addr$1 = {
178
- contents: "0x0000000000000000000000000000000000000000"
179
- };
180
- chainConfig.contracts.forEach(contract => {
181
- if (contract.name !== match) {
182
- return;
183
- }
184
- let a = contract.addresses[0];
185
- if (a !== undefined) {
186
- addr$1.contents = Primitive_option.valFromOption(a);
187
- return;
188
- }
189
- });
190
- srcAddress = addr$1.contents;
191
- }
230
+ let srcAddress = deriveSrcAddress(rawJson.srcAddress, eventConfig, chainConfig);
192
231
  let blockJson = rawJson.block;
193
232
  let blockJson$1 = (blockJson == null) ? undefined : Primitive_option.some(blockJson);
194
233
  let transactionJson = rawJson.transaction;
@@ -241,6 +280,7 @@ function parse(simulateItems, config, chainConfig) {
241
280
  blockNumber: blockNumber,
242
281
  blockHash: match$3[3],
243
282
  logIndex: logIndex,
283
+ transactionIndex: 0,
244
284
  payload: {
245
285
  contractName: eventConfig.contractName,
246
286
  eventName: eventConfig.name,
@@ -248,7 +288,7 @@ function parse(simulateItems, config, chainConfig) {
248
288
  chainId: chainId,
249
289
  srcAddress: srcAddress,
250
290
  logIndex: logIndex,
251
- transaction: transaction,
291
+ transaction: Primitive_option.some(transaction),
252
292
  block: match$3[0]
253
293
  }
254
294
  });
@@ -317,6 +357,10 @@ export {
317
357
  fuelSimulateTransactionSchema,
318
358
  parseFuelSimulateTransaction,
319
359
  findEventConfig,
360
+ dummySrcAddress,
361
+ firstContractAddress,
362
+ deriveSrcAddress,
363
+ validateSrcAddresses,
320
364
  parse,
321
365
  patchConfig,
322
366
  }
@@ -43,6 +43,33 @@ let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingA
43
43
  registrationBlock: dc.registrationBlock,
44
44
  }
45
45
 
46
+ // All indexing addresses (config-seeded + dynamically registered) grouped by
47
+ // chain id string, derived from the envio_addresses entities.
48
+ let getIndexingAddressesByChain = (state: testIndexerState): dict<
49
+ array<Internal.indexingAddress>,
50
+ > => {
51
+ let byChain = Dict.make()
52
+ switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
53
+ | Some(dcDict) =>
54
+ dcDict
55
+ ->Dict.valuesToArray
56
+ ->Array.forEach(entity => {
57
+ let dc = entity->castToEnvioAddresses
58
+ let chainIdStr = dc.chainId->Int.toString
59
+ let contracts = switch byChain->Dict.get(chainIdStr) {
60
+ | Some(arr) => arr
61
+ | None =>
62
+ let arr = []
63
+ byChain->Dict.set(chainIdStr, arr)
64
+ arr
65
+ }
66
+ contracts->Array.push(dc->toIndexingAddress)->ignore
67
+ })
68
+ | None => ()
69
+ }
70
+ byChain
71
+ }
72
+
46
73
  let handleLoad = (state: testIndexerState, ~tableName: string, ~filter: EntityFilter.t): JSON.t => {
47
74
  // Loads for non-entity tables (e.g. effect caches `envio_effect_<name>`) reach
48
75
  // here too. TestIndexer never persists those, so there's nothing to return —
@@ -566,22 +593,10 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
566
593
  `Cannot access ${contract.name}.addresses while indexer.process() is running. ` ++ "Wait for process() to complete before reading contract addresses.",
567
594
  )
568
595
  }
569
- let addresses = []
570
- switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
571
- | Some(dcDict) =>
572
- dcDict
573
- ->Dict.valuesToArray
574
- ->Array.forEach(
575
- entity => {
576
- let dc = entity->castToEnvioAddresses
577
- if dc.contractName === contract.name && dc.chainId === chainConfig.id {
578
- addresses->Array.push(dc->Config.EnvioAddresses.getAddress)->ignore
579
- }
580
- },
581
- )
582
- | None => ()
583
- }
584
- addresses
596
+ getIndexingAddressesByChain(state)
597
+ ->Dict.get(chainConfig.id->Int.toString)
598
+ ->Option.getOr([])
599
+ ->Array.filterMap(ia => ia.contractName === contract.name ? Some(ia.address) : None)
585
600
  },
586
601
  },
587
602
  )
@@ -653,6 +668,7 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
653
668
  })
654
669
 
655
670
  // Parse and validate all chain configs upfront before starting any workers
671
+ let preflightAddressesByChain = getIndexingAddressesByChain(state)
656
672
  let chainEntries = sortedChainKeys->Array.map(chainIdStr => {
657
673
  let rawChainConfig = rawChains->Dict.getUnsafe(chainIdStr)
658
674
  let chainId = switch chainIdStr->Int.fromString {
@@ -668,6 +684,19 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
668
684
  ~rawChainConfig,
669
685
  ~progressBlock=state.progressBlockByChain->Dict.get(chainIdStr),
670
686
  )
687
+ switch rawChainConfig.simulate {
688
+ | Some(simulateItems) =>
689
+ let chainConfig = config.chainMap->ChainMap.get(ChainMap.Chain.makeUnsafe(~chainId))
690
+ SimulateItems.validateSrcAddresses(
691
+ ~simulateItems,
692
+ ~config,
693
+ ~chainConfig,
694
+ ~indexingAddresses=preflightAddressesByChain
695
+ ->Dict.get(chainIdStr)
696
+ ->Option.getOr([]),
697
+ )
698
+ | None => ()
699
+ }
671
700
  (chainIdStr, chainId, rawChainConfig, processChainConfig)
672
701
  })
673
702
 
@@ -684,26 +713,9 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
684
713
  let chains: dict<chainConfig> = Dict.make()
685
714
  chains->Dict.set(chainIdStr, processChainConfig)
686
715
 
687
- // Extract dynamic contracts from state.entities for each chain
688
- let indexingAddressesByChain: dict<array<Internal.indexingAddress>> = Dict.make()
689
- switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
690
- | Some(dcDict) =>
691
- dcDict
692
- ->Dict.valuesToArray
693
- ->Array.forEach(entity => {
694
- let dc = entity->castToEnvioAddresses
695
- let dcChainIdStr = dc.chainId->Int.toString
696
- let contracts = switch indexingAddressesByChain->Dict.get(dcChainIdStr) {
697
- | Some(arr) => arr
698
- | None =>
699
- let arr = []
700
- indexingAddressesByChain->Dict.set(dcChainIdStr, arr)
701
- arr
702
- }
703
- contracts->Array.push(dc->toIndexingAddress)->ignore
704
- })
705
- | None => ()
706
- }
716
+ // Rebuilt per chain so workers see contracts registered by earlier
717
+ // chains in the same process() call.
718
+ let indexingAddressesByChain = getIndexingAddressesByChain(state)
707
719
 
708
720
  let initialState = makeInitialState(
709
721
  ~config,
@@ -12,6 +12,7 @@ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
12
12
  import * as Persistence from "./Persistence.res.mjs";
13
13
  import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
14
14
  import * as EntityFilter from "./db/EntityFilter.res.mjs";
15
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
15
16
  import * as InternalTable from "./db/InternalTable.res.mjs";
16
17
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
17
18
  import * as SimulateItems from "./SimulateItems.res.mjs";
@@ -32,6 +33,27 @@ function toIndexingAddress(dc) {
32
33
  };
33
34
  }
34
35
 
36
+ function getIndexingAddressesByChain(state) {
37
+ let byChain = {};
38
+ let dcDict = state.entities[Config.EnvioAddresses.name];
39
+ if (dcDict !== undefined) {
40
+ Object.values(dcDict).forEach(entity => {
41
+ let chainIdStr = entity.chain_id.toString();
42
+ let arr = byChain[chainIdStr];
43
+ let contracts;
44
+ if (arr !== undefined) {
45
+ contracts = arr;
46
+ } else {
47
+ let arr$1 = [];
48
+ byChain[chainIdStr] = arr$1;
49
+ contracts = arr$1;
50
+ }
51
+ contracts.push(toIndexingAddress(entity));
52
+ });
53
+ }
54
+ return byChain;
55
+ }
56
+
35
57
  function handleLoad(state, tableName, filter) {
36
58
  let entityConfig = state.entityConfigs[tableName];
37
59
  if (entityConfig === undefined) {
@@ -403,17 +425,11 @@ function makeCreateTestIndexer(config, workerPath) {
403
425
  if (state.processInProgress) {
404
426
  Stdlib_JsError.throwWithMessage(`Cannot access ` + contract.name + `.addresses while indexer.process() is running. ` + "Wait for process() to complete before reading contract addresses.");
405
427
  }
406
- let addresses = [];
407
- let dcDict = state.entities[Config.EnvioAddresses.name];
408
- if (dcDict !== undefined) {
409
- Object.values(dcDict).forEach(entity => {
410
- if (entity.contract_name === contract.name && entity.chain_id === chainConfig.id) {
411
- addresses.push(Config.EnvioAddresses.getAddress(entity));
412
- return;
413
- }
414
- });
415
- }
416
- return addresses;
428
+ return Stdlib_Array.filterMap(Stdlib_Option.getOr(getIndexingAddressesByChain(state)[chainConfig.id.toString()], []), ia => {
429
+ if (ia.contractName === contract.name) {
430
+ return Primitive_option.some(ia.address);
431
+ }
432
+ });
417
433
  }
418
434
  });
419
435
  Object.defineProperty(chainObj, contract.name, {
@@ -465,11 +481,17 @@ function makeCreateTestIndexer(config, workerPath) {
465
481
  let bId = Stdlib_Option.getOr(Stdlib_Int.fromString(b, undefined), 0);
466
482
  return Primitive_int.compare(aId, bId);
467
483
  });
484
+ let preflightAddressesByChain = getIndexingAddressesByChain(state);
468
485
  let chainEntries = sortedChainKeys.map(chainIdStr => {
469
486
  let rawChainConfig = rawChains[chainIdStr];
470
487
  let id = Stdlib_Int.fromString(chainIdStr, undefined);
471
488
  let chainId = id !== undefined ? id : Stdlib_JsError.throwWithMessage(`Invalid chain ID "` + chainIdStr + `": expected a numeric chain ID`);
472
489
  let processChainConfig = parseBlockRange(chainIdStr, config, rawChainConfig, state.progressBlockByChain[chainIdStr]);
490
+ let simulateItems = rawChainConfig.simulate;
491
+ if (simulateItems !== undefined) {
492
+ let chainConfig = ChainMap.get(config.chainMap, ChainMap.Chain.makeUnsafe(chainId));
493
+ SimulateItems.validateSrcAddresses(simulateItems, config, chainConfig, Stdlib_Option.getOr(preflightAddressesByChain[chainIdStr], []));
494
+ }
473
495
  return [
474
496
  chainIdStr,
475
497
  chainId,
@@ -484,23 +506,7 @@ function makeCreateTestIndexer(config, workerPath) {
484
506
  let chainId = param[1];
485
507
  let chains = {};
486
508
  chains[param[0]] = processChainConfig;
487
- let indexingAddressesByChain = {};
488
- let dcDict = state.entities[Config.EnvioAddresses.name];
489
- if (dcDict !== undefined) {
490
- Object.values(dcDict).forEach(entity => {
491
- let dcChainIdStr = entity.chain_id.toString();
492
- let arr = indexingAddressesByChain[dcChainIdStr];
493
- let contracts;
494
- if (arr !== undefined) {
495
- contracts = arr;
496
- } else {
497
- let arr$1 = [];
498
- indexingAddressesByChain[dcChainIdStr] = arr$1;
499
- contracts = arr$1;
500
- }
501
- contracts.push(toIndexingAddress(entity));
502
- });
503
- }
509
+ let indexingAddressesByChain = getIndexingAddressesByChain(state);
504
510
  let initialState = makeInitialState(config, chains, indexingAddressesByChain);
505
511
  return new Promise((resolve, reject) => {
506
512
  let workerData_startBlock = processChainConfig.startBlock;
@@ -645,6 +651,7 @@ function initTestWorker() {
645
651
 
646
652
  export {
647
653
  toIndexingAddress,
654
+ getIndexingAddressesByChain,
648
655
  handleLoad,
649
656
  handleWriteBatch,
650
657
  makeInitialState,
@@ -0,0 +1,7 @@
1
+ type timeRef = float
2
+
3
+ @val @scope("performance") external now: unit => timeRef = "now"
4
+
5
+ let secondsSince = (from: timeRef): float => (now() -. from) /. 1000.
6
+
7
+ let secondsBetween = (~from: timeRef, ~to: timeRef): float => (to -. from) /. 1000.
@@ -0,0 +1,21 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+
4
+ function secondsSince(from) {
5
+ return (performance.now() - from) / 1000;
6
+ }
7
+
8
+ function secondsBetween(from, to) {
9
+ return (to - from) / 1000;
10
+ }
11
+
12
+ function now(prim) {
13
+ return performance.now();
14
+ }
15
+
16
+ export {
17
+ now,
18
+ secondsSince,
19
+ secondsBetween,
20
+ }
21
+ /* No side effect */
@@ -0,0 +1,7 @@
1
+ type timeRef = float
2
+
3
+ let now: unit => timeRef
4
+
5
+ let secondsSince: timeRef => float
6
+
7
+ let secondsBetween: (~from: timeRef, ~to: timeRef) => float
@@ -28,29 +28,25 @@ module Group = {
28
28
  }
29
29
  }
30
30
 
31
- let get = (
32
- group: t<'a>,
33
- ~contractAddress,
34
- ~blockNumber,
35
- ~indexingAddresses: dict<FetchState.indexingAddress>,
36
- ) =>
31
+ // Ownership only: resolve the owning contract from the partition's reverse
32
+ // index (the partition that fetched the log), not a chain-wide snapshot. The
33
+ // `effectiveStartBlock` temporal gate now lives in `clientAddressFilter`. The
34
+ // wildcard partition has an empty index → every log falls back to `wildcard`,
35
+ // so it can never claim an address-bound contract's logs.
36
+ let get = (group: t<'a>, ~contractAddress, ~contractNameByAddress: dict<string>) =>
37
37
  switch group {
38
38
  | {wildcard, byContractName} =>
39
- switch indexingAddresses->Utils.Dict.dangerouslyGetNonOption(
39
+ switch contractNameByAddress->Utils.Dict.dangerouslyGetNonOption(
40
40
  contractAddress->Address.toString,
41
41
  ) {
42
- | Some(indexingContract) =>
43
- if indexingContract.effectiveStartBlock <= blockNumber {
44
- switch byContractName->Utils.Dict.dangerouslyGetNonOption(indexingContract.contractName) {
45
- // Fall back to the wildcard handler when the indexed contract has no
46
- // matching event for this tag. This covers addresses registered for
47
- // contracts without events (persisted for future config changes) as
48
- // well as addresses whose contract has other events but not this one.
49
- | None => wildcard
50
- | Some(_) as event => event
51
- }
52
- } else {
53
- None
42
+ | Some(contractName) =>
43
+ switch byContractName->Utils.Dict.dangerouslyGetNonOption(contractName) {
44
+ // Fall back to the wildcard handler when the owning contract has no
45
+ // matching event for this tag. This covers addresses registered for
46
+ // contracts without events (persisted for future config changes) as
47
+ // well as addresses whose contract has other events but not this one.
48
+ | None => wildcard
49
+ | Some(_) as event => event
54
50
  }
55
51
  | None => wildcard
56
52
  }
@@ -89,10 +85,10 @@ let addOrThrow = (
89
85
  }
90
86
  }
91
87
 
92
- let get = (router: t<'a>, ~tag, ~contractAddress, ~blockNumber, ~indexingAddresses) => {
88
+ let get = (router: t<'a>, ~tag, ~contractAddress, ~contractNameByAddress) => {
93
89
  switch router->Utils.Dict.dangerouslyGetNonOption(tag) {
94
90
  | None => None
95
- | Some(group) => group->Group.get(~contractAddress, ~blockNumber, ~indexingAddresses)
91
+ | Some(group) => group->Group.get(~contractAddress, ~contractNameByAddress)
96
92
  }
97
93
  }
98
94
 
@@ -39,16 +39,13 @@ function addOrThrow(group, event, contractName, isWildcard) {
39
39
  byContractName[contractName] = event;
40
40
  }
41
41
 
42
- function get(group, contractAddress, blockNumber, indexingAddresses) {
42
+ function get(group, contractAddress, contractNameByAddress) {
43
43
  let wildcard = group.wildcard;
44
- let indexingContract = indexingAddresses[contractAddress];
45
- if (indexingContract === undefined) {
44
+ let contractName = contractNameByAddress[contractAddress];
45
+ if (contractName === undefined) {
46
46
  return wildcard;
47
47
  }
48
- if (indexingContract.effectiveStartBlock > blockNumber) {
49
- return;
50
- }
51
- let event = group.byContractName[indexingContract.contractName];
48
+ let event = group.byContractName[contractName];
52
49
  if (event !== undefined) {
53
50
  return event;
54
51
  } else {
@@ -93,10 +90,10 @@ function addOrThrow$1(router, eventId, event, contractName, isWildcard, eventNam
93
90
  }
94
91
  }
95
92
 
96
- function get$1(router, tag, contractAddress, blockNumber, indexingAddresses) {
93
+ function get$1(router, tag, contractAddress, contractNameByAddress) {
97
94
  let group = router[tag];
98
95
  if (group !== undefined) {
99
- return get(group, contractAddress, blockNumber, indexingAddresses);
96
+ return get(group, contractAddress, contractNameByAddress);
100
97
  }
101
98
  }
102
99
 
@@ -1,5 +1,7 @@
1
1
  // EVM's concrete item payload. Erased to `Internal.eventPayload` on the item
2
- // and recovered here via `toPayload`.
2
+ // and recovered here via `toPayload`. HyperSync omits `transaction` (it lives
3
+ // raw in the per-chain store and is written onto the payload at batch prep);
4
+ // RPC/simulate build it inline.
3
5
  type payload = {
4
6
  contractName: string,
5
7
  eventName: string,
@@ -7,12 +9,51 @@ type payload = {
7
9
  chainId: int,
8
10
  srcAddress: Address.t,
9
11
  logIndex: int,
10
- transaction: Internal.eventTransaction,
12
+ transaction?: Internal.eventTransaction,
11
13
  block: Internal.eventBlock,
12
14
  }
13
15
  external fromPayload: payload => Internal.eventPayload = "%identity"
14
16
  external toPayload: Internal.eventPayload => payload = "%identity"
15
17
 
18
+ // Ordered transaction field names. The index of each is the field code shared
19
+ // with the Rust store (`EvmTxField`) — keep this order in sync.
20
+ let transactionFields = [
21
+ "transactionIndex",
22
+ "hash",
23
+ "from",
24
+ "to",
25
+ "gas",
26
+ "gasPrice",
27
+ "maxPriorityFeePerGas",
28
+ "maxFeePerGas",
29
+ "cumulativeGasUsed",
30
+ "effectiveGasPrice",
31
+ "gasUsed",
32
+ "input",
33
+ "nonce",
34
+ "value",
35
+ "v",
36
+ "r",
37
+ "s",
38
+ "contractAddress",
39
+ "logsBloom",
40
+ "root",
41
+ "status",
42
+ "yParity",
43
+ "maxFeePerBlobGas",
44
+ "blobVersionedHashes",
45
+ "type",
46
+ "l1Fee",
47
+ "l1GasPrice",
48
+ "l1GasUsed",
49
+ "l1FeeScalar",
50
+ "gasUsedForL1",
51
+ "accessList",
52
+ "authorizationList",
53
+ ]
54
+
55
+ let transactionFieldMask = TransactionStore.makeMaskFn(transactionFields)
56
+
16
57
  let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
17
58
  delete fields.hash
18
59
  delete fields.number
@@ -21,70 +62,6 @@ let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
21
62
 
22
63
  let make = (~logger: Pino.t): Ecosystem.t => {
23
64
  name: Evm,
24
- blockFields: [
25
- "number",
26
- "timestamp",
27
- "hash",
28
- "parentHash",
29
- "nonce",
30
- "sha3Uncles",
31
- "logsBloom",
32
- "transactionsRoot",
33
- "stateRoot",
34
- "receiptsRoot",
35
- "miner",
36
- "difficulty",
37
- "totalDifficulty",
38
- "extraData",
39
- "size",
40
- "gasLimit",
41
- "gasUsed",
42
- "uncles",
43
- "baseFeePerGas",
44
- "blobGasUsed",
45
- "excessBlobGas",
46
- "parentBeaconBlockRoot",
47
- "withdrawalsRoot",
48
- "l1BlockNumber",
49
- "sendCount",
50
- "sendRoot",
51
- "mixHash",
52
- ],
53
- transactionFields: [
54
- "transactionIndex",
55
- "hash",
56
- "from",
57
- "to",
58
- "gas",
59
- "gasPrice",
60
- "maxPriorityFeePerGas",
61
- "maxFeePerGas",
62
- "cumulativeGasUsed",
63
- "effectiveGasPrice",
64
- "gasUsed",
65
- "input",
66
- "nonce",
67
- "value",
68
- "v",
69
- "r",
70
- "s",
71
- "contractAddress",
72
- "logsBloom",
73
- "root",
74
- "status",
75
- "yParity",
76
- "chainId",
77
- "maxFeePerBlobGas",
78
- "blobVersionedHashes",
79
- "type",
80
- "l1Fee",
81
- "l1GasPrice",
82
- "l1GasUsed",
83
- "l1FeeScalar",
84
- "gasUsedForL1",
85
- "accessList",
86
- "authorizationList",
87
- ],
88
65
  blockNumberName: "number",
89
66
  blockTimestampName: "timestamp",
90
67
  blockHashName: "hash",
@@ -106,7 +83,10 @@ let make = (~logger: Pino.t): Ecosystem.t => {
106
83
  s.field("block", S.option(S.object(s2 => s2.field("number", S.unknown))))
107
84
  ),
108
85
  logger,
109
- toEvent: eventItem => eventItem.payload->Internal.payloadToEvent,
86
+ transactionFieldMask,
87
+ // The payload carries `transaction` by batch prep (HyperSync) or inline
88
+ // (RPC/simulate), so the event is the payload as-is.
89
+ toEvent: eventItem => eventItem.payload->(Utils.magic: Internal.eventPayload => Internal.event),
110
90
  toEventLogger: eventItem =>
111
91
  Logging.createChildFrom(
112
92
  ~logger,