envio 3.3.0-alpha.10 → 3.3.0-alpha.12

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 (60) 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 +30 -18
  8. package/src/ChainFetching.res.mjs +23 -13
  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 +64 -29
  17. package/src/CrossChainState.res.mjs +17 -8
  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 +428 -322
  23. package/src/FetchState.res.mjs +316 -233
  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/Rollback.res +32 -13
  31. package/src/Rollback.res.mjs +24 -11
  32. package/src/SimulateDeadInputTracker.res +1 -1
  33. package/src/SimulateItems.res +38 -6
  34. package/src/SimulateItems.res.mjs +28 -9
  35. package/src/TestIndexer.res +2 -2
  36. package/src/TestIndexer.res.mjs +2 -2
  37. package/src/TopicFilter.res +1 -25
  38. package/src/TopicFilter.res.mjs +0 -74
  39. package/src/bindings/Viem.res +0 -5
  40. package/src/sources/EventRouter.res +0 -21
  41. package/src/sources/EventRouter.res.mjs +0 -12
  42. package/src/sources/EvmChain.res +2 -27
  43. package/src/sources/EvmChain.res.mjs +2 -23
  44. package/src/sources/EvmRpcClient.res +12 -15
  45. package/src/sources/EvmRpcClient.res.mjs +3 -3
  46. package/src/sources/HyperSync.res +9 -38
  47. package/src/sources/HyperSync.res.mjs +16 -28
  48. package/src/sources/HyperSync.resi +2 -2
  49. package/src/sources/HyperSyncClient.res +88 -11
  50. package/src/sources/HyperSyncClient.res.mjs +39 -6
  51. package/src/sources/HyperSyncSource.res +18 -199
  52. package/src/sources/HyperSyncSource.res.mjs +9 -128
  53. package/src/sources/Rpc.res +0 -32
  54. package/src/sources/Rpc.res.mjs +1 -46
  55. package/src/sources/RpcSource.res +29 -175
  56. package/src/sources/RpcSource.res.mjs +32 -110
  57. package/src/sources/SimulateSource.res +37 -19
  58. package/src/sources/SimulateSource.res.mjs +27 -10
  59. package/src/sources/SvmHyperSyncSource.res +13 -3
  60. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
@@ -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.
@@ -8,75 +8,6 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
8
8
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
9
9
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
10
10
 
11
- let MissingRequiredTopic0 = /* @__PURE__ */Primitive_exceptions.create("LogSelection.MissingRequiredTopic0");
12
-
13
- function makeTopicSelection(topic0, topic1Opt, topic2Opt, topic3Opt) {
14
- let topic1 = topic1Opt !== undefined ? topic1Opt : [];
15
- let topic2 = topic2Opt !== undefined ? topic2Opt : [];
16
- let topic3 = topic3Opt !== undefined ? topic3Opt : [];
17
- if (Utils.$$Array.isEmpty(topic0)) {
18
- return {
19
- TAG: "Error",
20
- _0: {
21
- RE_EXN_ID: MissingRequiredTopic0
22
- }
23
- };
24
- } else {
25
- return {
26
- TAG: "Ok",
27
- _0: {
28
- topic0: topic0,
29
- topic1: topic1,
30
- topic2: topic2,
31
- topic3: topic3
32
- }
33
- };
34
- }
35
- }
36
-
37
- function hasFilters(param) {
38
- return Stdlib_Option.isSome([
39
- param.topic1,
40
- param.topic2,
41
- param.topic3
42
- ].find(topic => !Utils.$$Array.isEmpty(topic)));
43
- }
44
-
45
- function compressTopicSelections(topicSelections) {
46
- let topic0sOfSelectionsWithoutFilters = [];
47
- let selectionsWithFilters = [];
48
- topicSelections.forEach(selection => {
49
- if (hasFilters(selection)) {
50
- selectionsWithFilters.push(selection);
51
- } else {
52
- selection.topic0.forEach(topic0 => {
53
- topic0sOfSelectionsWithoutFilters.push(topic0);
54
- });
55
- }
56
- });
57
- if (topic0sOfSelectionsWithoutFilters.length === 0) {
58
- return selectionsWithFilters;
59
- }
60
- let selectionWithoutFilters_topic1 = [];
61
- let selectionWithoutFilters_topic2 = [];
62
- let selectionWithoutFilters_topic3 = [];
63
- let selectionWithoutFilters = {
64
- topic0: topic0sOfSelectionsWithoutFilters,
65
- topic1: selectionWithoutFilters_topic1,
66
- topic2: selectionWithoutFilters_topic2,
67
- topic3: selectionWithoutFilters_topic3
68
- };
69
- return [selectionWithoutFilters].concat(selectionsWithFilters);
70
- }
71
-
72
- function make(addresses, topicSelections) {
73
- let topicSelections$1 = compressTopicSelections(topicSelections);
74
- return {
75
- addresses: addresses,
76
- topicSelections: topicSelections$1
77
- };
78
- }
79
-
80
11
  function materializeTopicFilter(filter, addresses) {
81
12
  if (filter.TAG === "Values") {
82
13
  return filter._0;
@@ -299,11 +230,6 @@ function parseWhereOrThrow(where, sighash, params, contractName, chainId, onEven
299
230
  }
300
231
 
301
232
  export {
302
- MissingRequiredTopic0,
303
- makeTopicSelection,
304
- hasFilters,
305
- compressTopicSelections,
306
- make,
307
233
  materializeTopicFilter,
308
234
  materializeTopicSelections,
309
235
  eventBlockRangeSchema,
package/src/RawEvent.res CHANGED
@@ -32,8 +32,8 @@ let make = (
32
32
  ~blockTimestamp: int,
33
33
  ~cleanUpRawEventFieldsInPlace: JSON.t => unit,
34
34
  ): Internal.rawEvent => {
35
- let {onEventRegistration, chain, blockNumber, logIndex} = eventItem
36
- let eventConfig = onEventRegistration.eventConfig
35
+ let {chain, blockNumber, logIndex} = eventItem
36
+ let eventConfig = eventItem.onEventRegistration.eventConfig
37
37
  let chainId = chain->ChainMap.Chain.toChainId
38
38
  let eventId = EventUtils.packEventIndex(~logIndex, ~blockNumber)
39
39
  let blockFields =
package/src/Rollback.res CHANGED
@@ -72,7 +72,7 @@ let rec rollback = async (
72
72
  // found yet. Wait for the ReorgDetected branch above to find it and re-kick.
73
73
  | FindingReorgDepth => ()
74
74
  | FoundReorgDepth(_) if state->IndexerState.isProcessing =>
75
- Logging.info("Waiting for batch to finish processing before executing rollback")
75
+ Logging.trace("Waiting for batch to finish processing before executing rollback")
76
76
  | FoundReorgDepth({chain: reorgChain, rollbackTargetBlockNumber}) =>
77
77
  await executeRollback(
78
78
  state,
@@ -96,10 +96,10 @@ and executeRollback = async (
96
96
  ) => {
97
97
  let startTime = Performance.now()
98
98
 
99
- let chainState = state->IndexerState.getChainState(~chain=reorgChain)
100
-
101
- let logger = Logging.createChildFrom(
102
- ~logger=chainState->ChainState.logger,
99
+ // Not derived from the reorg chain's logger: that would bind its chainId onto
100
+ // every line, colliding with the per-chain chainId on the "Rollbacked" logs.
101
+ // The reorg chain is identified by the reorgChain param instead.
102
+ let logger = Logging.createChild(
103
103
  ~params={
104
104
  "action": "Rollback",
105
105
  "reorgChain": reorgChain,
@@ -161,10 +161,12 @@ and executeRollback = async (
161
161
  }
162
162
  }
163
163
 
164
+ let rolledBackChains = []
164
165
  state
165
166
  ->IndexerState.chainStates
166
167
  ->Utils.Dict.forEach(cs => {
167
168
  let chainId = (cs->ChainState.chainConfig).id
169
+ let fromBlock = cs->ChainState.committedProgressBlockNumber
168
170
  cs->ChainState.rollback(
169
171
  ~newProgressBlockNumber=newProgressBlockNumberPerChain->Utils.Dict.dangerouslyGetByIntNonOption(
170
172
  chainId,
@@ -175,6 +177,19 @@ and executeRollback = async (
175
177
  ~rollbackTargetBlockNumber,
176
178
  ~isReorgChain=chainId === reorgChainId,
177
179
  )
180
+ let toBlock = cs->ChainState.committedProgressBlockNumber
181
+ if fromBlock !== toBlock {
182
+ rolledBackChains
183
+ ->Array.push({
184
+ "chainId": chainId,
185
+ "fromBlock": fromBlock,
186
+ "toBlock": toBlock,
187
+ "rollbackedEvents": eventsProcessedDiffByChain
188
+ ->Utils.Dict.dangerouslyGetByIntNonOption(chainId)
189
+ ->Option.getOr(0.),
190
+ })
191
+ ->ignore
192
+ }
178
193
  })
179
194
 
180
195
  let diff = await state->InMemoryStore.prepareRollbackDiff(
@@ -183,15 +198,19 @@ and executeRollback = async (
183
198
  ~progressBlockNumberByChainId=newProgressBlockNumberPerChain,
184
199
  )
185
200
 
201
+ rolledBackChains->Array.forEach(chain => {
202
+ logger->Logging.childInfo({
203
+ "msg": "Rollbacked",
204
+ "chainId": chain["chainId"],
205
+ "fromBlock": chain["fromBlock"],
206
+ "toBlock": chain["toBlock"],
207
+ "rollbackedEvents": chain["rollbackedEvents"],
208
+ })
209
+ })
186
210
  logger->Logging.childTrace({
187
- "msg": "Finished rollback on reorg",
188
- "entityChanges": {
189
- "deleted": diff["deletedEntities"],
190
- "upserted": diff["setEntities"],
191
- },
192
- "rollbackedEvents": rollbackedProcessedEvents.contents,
193
- "beforeCheckpointId": state->IndexerState.committedCheckpointId,
194
- "targetCheckpointId": rollbackTargetCheckpointId,
211
+ "msg": "Rollback entity changes",
212
+ "deleted": diff["deletedEntities"],
213
+ "upserted": diff["setEntities"],
195
214
  })
196
215
  Prometheus.RollbackSuccess.increment(
197
216
  ~timeSeconds=Performance.secondsSince(startTime),
@@ -33,8 +33,7 @@ async function getLastKnownValidBlock(chainState, reorgBlockNumber, isRealtime)
33
33
 
34
34
  async function executeRollback(state, reorgChain, rollbackTargetBlockNumber, scheduleFetch, scheduleProcessing) {
35
35
  let startTime = Performance.now();
36
- let chainState = IndexerState.getChainState(state, reorgChain);
37
- let logger = Logging.createChildFrom(ChainState.logger(chainState), {
36
+ let logger = Logging.createChild({
38
37
  action: "Rollback",
39
38
  reorgChain: reorgChain,
40
39
  targetBlockNumber: rollbackTargetBlockNumber
@@ -55,20 +54,34 @@ async function executeRollback(state, reorgChain, rollbackTargetBlockNumber, sch
55
54
  eventsProcessedDiffByChain[diff.chain_id] = eventsProcessedDiff;
56
55
  newProgressBlockNumberPerChain[diff.chain_id] = rollbackTargetCheckpointId === 0n && diff.chain_id === reorgChain ? Primitive_int.min(diff.new_progress_block_number, rollbackTargetBlockNumber) : diff.new_progress_block_number;
57
56
  }
57
+ let rolledBackChains = [];
58
58
  Utils.Dict.forEach(IndexerState.chainStates(state), cs => {
59
59
  let chainId = ChainState.chainConfig(cs).id;
60
+ let fromBlock = ChainState.committedProgressBlockNumber(cs);
60
61
  ChainState.rollback(cs, newProgressBlockNumberPerChain[chainId], eventsProcessedDiffByChain[chainId], rollbackTargetBlockNumber, chainId === reorgChain);
62
+ let toBlock = ChainState.committedProgressBlockNumber(cs);
63
+ if (fromBlock !== toBlock) {
64
+ rolledBackChains.push({
65
+ chainId: chainId,
66
+ fromBlock: fromBlock,
67
+ toBlock: toBlock,
68
+ rollbackedEvents: Stdlib_Option.getOr(eventsProcessedDiffByChain[chainId], 0)
69
+ });
70
+ return;
71
+ }
61
72
  });
62
73
  let diff$1 = await InMemoryStore.prepareRollbackDiff(state, rollbackTargetCheckpointId, IndexerState.committedCheckpointId(state) + 1n, newProgressBlockNumberPerChain);
74
+ rolledBackChains.forEach(chain => Logging.childInfo(logger, {
75
+ msg: "Rollbacked",
76
+ chainId: chain.chainId,
77
+ fromBlock: chain.fromBlock,
78
+ toBlock: chain.toBlock,
79
+ rollbackedEvents: chain.rollbackedEvents
80
+ }));
63
81
  Logging.childTrace(logger, {
64
- msg: "Finished rollback on reorg",
65
- entityChanges: {
66
- deleted: diff$1.deletedEntities,
67
- upserted: diff$1.setEntities
68
- },
69
- rollbackedEvents: rollbackedProcessedEvents,
70
- beforeCheckpointId: IndexerState.committedCheckpointId(state),
71
- targetCheckpointId: rollbackTargetCheckpointId
82
+ msg: "Rollback entity changes",
83
+ deleted: diff$1.deletedEntities,
84
+ upserted: diff$1.setEntities
72
85
  });
73
86
  Prometheus.RollbackSuccess.increment(Performance.secondsSince(startTime), rollbackedProcessedEvents);
74
87
  IndexerState.completeRollback(state, eventsProcessedDiffByChain);
@@ -97,7 +110,7 @@ async function rollback(state, scheduleFetch, scheduleProcessing, scheduleRollba
97
110
  return scheduleRollback();
98
111
  case "FoundReorgDepth" :
99
112
  if (IndexerState.isProcessing(state)) {
100
- return Logging.info("Waiting for batch to finish processing before executing rollback");
113
+ return Logging.trace("Waiting for batch to finish processing before executing rollback");
101
114
  } else {
102
115
  return await executeRollback(state, match.chain, match.rollbackTargetBlockNumber, scheduleFetch, scheduleProcessing);
103
116
  }
@@ -10,7 +10,7 @@ let itemKey = (item: Internal.item): string =>
10
10
  `${chain
11
11
  ->ChainMap.Chain.toChainId
12
12
  ->Int.toString}:${blockNumber->Int.toString}:${logIndex->Int.toString}`
13
- | _ => "" // non-event items are never a provided simulate input
13
+ | Internal.Block(_) => ""
14
14
  }
15
15
 
16
16
  // `index` is the item's position in its chain's `simulate` array, reported back
@@ -240,9 +240,12 @@ let deriveSrcAddress = (
240
240
  }
241
241
  }
242
242
 
243
- let parse = (~simulateItems: array<JSON.t>, ~config: Config.t, ~chainConfig: Config.chain): array<
244
- Internal.item,
245
- > => {
243
+ let parse = (
244
+ ~simulateItems: array<JSON.t>,
245
+ ~config: Config.t,
246
+ ~chainConfig: Config.chain,
247
+ ~onEventRegistrations: array<Internal.onEventRegistration>,
248
+ ): array<Internal.item> => {
246
249
  let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
247
250
  let chainId = chainConfig.id
248
251
  let startBlock = chainConfig.startBlock
@@ -345,6 +348,11 @@ let parse = (~simulateItems: array<JSON.t>, ~config: Config.t, ~chainConfig: Con
345
348
  ~chainId,
346
349
  ~eventConfig,
347
350
  )
351
+ // Append into the registration array that the chain state will own and
352
+ // put that same registration object directly on the simulated item.
353
+ let onEventRegistrationIndex = onEventRegistrations->Array.length
354
+ let onEventRegistration = {...onEventRegistration, index: onEventRegistrationIndex}
355
+ onEventRegistrations->Array.push(onEventRegistration)->ignore
348
356
 
349
357
  items
350
358
  ->Array.push(
@@ -382,7 +390,11 @@ let parse = (~simulateItems: array<JSON.t>, ~config: Config.t, ~chainConfig: Con
382
390
 
383
391
  // Apply simulate source config from processConfig JSON to a Config.t
384
392
  // This patches chainMap entries that have simulate items with CustomSources
385
- let patchConfig = (~config: Config.t, ~processConfig: JSON.t): Config.t => {
393
+ let patchConfig = (
394
+ ~config: Config.t,
395
+ ~processConfig: JSON.t,
396
+ ~registrationsByChainId: HandlerRegister.registrationsByChainId,
397
+ ): Config.t => {
386
398
  let processChains: option<dict<JSON.t>> =
387
399
  (processConfig->(Utils.magic: JSON.t => {..}))["chains"]->Nullable.toOption
388
400
  switch processChains {
@@ -395,11 +407,31 @@ let patchConfig = (~config: Config.t, ~processConfig: JSON.t): Config.t => {
395
407
  let simulateRaw: option<array<JSON.t>> = raw["simulate"]->Nullable.toOption
396
408
  switch simulateRaw {
397
409
  | Some(simulateItems) =>
398
- let items = parse(~simulateItems, ~config, ~chainConfig)
410
+ let chainRegistrations = switch registrationsByChainId->Utils.Dict.dangerouslyGetNonOption(
411
+ chainIdStr,
412
+ ) {
413
+ | Some(registrations) => registrations
414
+ | None =>
415
+ let registrations: HandlerRegister.chainRegistrations = {
416
+ onEventRegistrations: [],
417
+ onBlockRegistrations: [],
418
+ }
419
+ registrationsByChainId->Dict.set(chainIdStr, registrations)
420
+ registrations
421
+ }
399
422
  let startBlock: int = raw["startBlock"]->(Utils.magic: 'a => int)
400
423
  let endBlock: int = raw["endBlock"]->(Utils.magic: 'a => int)
424
+ // Parse with the process's startBlock so items default into the range
425
+ // the source will be queried over; the source now filters by range.
426
+ let chainConfig = {...chainConfig, startBlock, endBlock}
427
+ let items = parse(
428
+ ~simulateItems,
429
+ ~config,
430
+ ~chainConfig,
431
+ ~onEventRegistrations=chainRegistrations.onEventRegistrations,
432
+ )
401
433
  let source = SimulateSource.make(~items, ~endBlock, ~chain)
402
- {...chainConfig, startBlock, endBlock, sourceConfig: Config.CustomSources([source])}
434
+ {...chainConfig, sourceConfig: Config.CustomSources([source])}
403
435
  | None => chainConfig
404
436
  }
405
437
  | None => chainConfig
@@ -167,7 +167,7 @@ function deriveSrcAddress(providedSrcAddress, eventConfig, chainConfig, config)
167
167
  }
168
168
  }
169
169
 
170
- function parse(simulateItems, config, chainConfig) {
170
+ function parse(simulateItems, config, chainConfig, onEventRegistrations) {
171
171
  let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
172
172
  let chainId = chainConfig.id;
173
173
  let startBlock = chainConfig.startBlock;
@@ -254,9 +254,13 @@ function parse(simulateItems, config, chainConfig) {
254
254
  seenCoordinates[coordinate] = itemIndex;
255
255
  }
256
256
  let onEventRegistration = HandlerRegister.buildOnEventRegistration(config, chainId, eventConfig, undefined);
257
+ let onEventRegistrationIndex = onEventRegistrations.length;
258
+ let newrecord = {...onEventRegistration};
259
+ newrecord.index = onEventRegistrationIndex;
260
+ onEventRegistrations.push(newrecord);
257
261
  items.push({
258
262
  kind: 0,
259
- onEventRegistration: onEventRegistration,
263
+ onEventRegistration: newrecord,
260
264
  chain: chain,
261
265
  blockNumber: blockNumber,
262
266
  logIndex: logIndex,
@@ -276,7 +280,7 @@ function parse(simulateItems, config, chainConfig) {
276
280
  return items;
277
281
  }
278
282
 
279
- function patchConfig(config, processConfig) {
283
+ function patchConfig(config, processConfig, registrationsByChainId) {
280
284
  let processChains = processConfig.chains;
281
285
  if (processChains == null) {
282
286
  return config;
@@ -291,18 +295,33 @@ function patchConfig(config, processConfig) {
291
295
  if (simulateRaw == null) {
292
296
  return chainConfig;
293
297
  }
294
- let items = parse(simulateRaw, config, chainConfig);
298
+ let registrations = registrationsByChainId[chainIdStr];
299
+ let chainRegistrations;
300
+ if (registrations !== undefined) {
301
+ chainRegistrations = registrations;
302
+ } else {
303
+ let registrations_onEventRegistrations = [];
304
+ let registrations_onBlockRegistrations = [];
305
+ let registrations$1 = {
306
+ onEventRegistrations: registrations_onEventRegistrations,
307
+ onBlockRegistrations: registrations_onBlockRegistrations
308
+ };
309
+ registrationsByChainId[chainIdStr] = registrations$1;
310
+ chainRegistrations = registrations$1;
311
+ }
295
312
  let startBlock = processChainJson.startBlock;
296
313
  let endBlock = processChainJson.endBlock;
297
- let source = SimulateSource.make(items, endBlock, chain);
298
314
  let newrecord = {...chainConfig};
299
- newrecord.sourceConfig = {
315
+ newrecord.endBlock = endBlock;
316
+ newrecord.startBlock = startBlock;
317
+ let items = parse(simulateRaw, config, newrecord, chainRegistrations.onEventRegistrations);
318
+ let source = SimulateSource.make(items, endBlock, chain);
319
+ let newrecord$1 = {...newrecord};
320
+ newrecord$1.sourceConfig = {
300
321
  TAG: "CustomSources",
301
322
  _0: [source]
302
323
  };
303
- newrecord.endBlock = endBlock;
304
- newrecord.startBlock = startBlock;
305
- return newrecord;
324
+ return newrecord$1;
306
325
  });
307
326
  return {
308
327
  name: config.name,
@@ -863,8 +863,8 @@ let initTestWorker = () => {
863
863
  | Some(_) => ()
864
864
  }
865
865
 
866
- let patchConfig = (config: Config.t, _registrations) => {
867
- let config = SimulateItems.patchConfig(~config, ~processConfig)
866
+ let patchConfig = (config: Config.t, registrationsByChainId) => {
867
+ let config = SimulateItems.patchConfig(~config, ~processConfig, ~registrationsByChainId)
868
868
 
869
869
  // In auto-exit mode, set batchSize=1 to process one block checkpoint at a time
870
870
  if exitAfterFirstEventBlock {
@@ -612,8 +612,8 @@ function initTestWorker() {
612
612
  } else {
613
613
  Logging.setLogLevel("silent");
614
614
  }
615
- let patchConfig = (config, _registrations) => {
616
- let config$1 = SimulateItems.patchConfig(config, processConfig);
615
+ let patchConfig = (config, registrationsByChainId) => {
616
+ let config$1 = SimulateItems.patchConfig(config, processConfig, registrationsByChainId);
617
617
  if (exitAfterFirstEventBlock) {
618
618
  return {
619
619
  name: config$1.name,
@@ -1,27 +1,3 @@
1
- let toTwosComplement = (num: bigint, ~bytesLen: int) => {
2
- let maxValue = 1n->BigInt.shiftLeft(BigInt.fromInt(bytesLen * 8))
3
- let mask = maxValue->BigInt.sub(1n)
4
- num->BigInt.add(maxValue)->BigInt.bitwiseAnd(mask)
5
- }
6
-
7
- let fromSignedBigInt = val => {
8
- let bytesLen = 32
9
- let val = val >= 0n ? val : val->toTwosComplement(~bytesLen)
10
- val->Viem.bigintToHex(~options={size: bytesLen})
11
- }
12
-
13
1
  type hex = EvmTypes.Hex.t
14
- //bytes currently does not work with genType and we also currently generate bytes as a string type
15
- type bytesHex = string
16
- let keccak256 = Viem.keccak256
17
- let bytesToHex = Viem.bytesToHex
18
- let concat = Viem.concat
19
- let castToHexUnsafe: 'a => hex = val => val->(Utils.magic: 'a => hex)
20
- let fromBigInt: bigint => hex = val => val->Viem.bigintToHex(~options={size: 32})
21
- let fromDynamicString: string => hex = val => val->(Utils.magic: string => hex)->keccak256
22
- let fromString: string => hex = val => val->Viem.stringToHex(~options={size: 32})
2
+
23
3
  let fromAddress: Address.t => hex = addr => addr->(Utils.magic: Address.t => hex)->Viem.pad
24
- let fromDynamicBytes: bytesHex => hex = bytes => bytes->(Utils.magic: bytesHex => hex)->keccak256
25
- let fromBytes: bytesHex => hex = bytes =>
26
- bytes->(Utils.magic: bytesHex => Uint8Array.t)->Viem.bytesToHex(~options={size: 32})
27
- let fromBool: bool => hex = b => b->Viem.boolToHex(~options={size: 32})
@@ -1,86 +1,12 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Viem from "viem";
4
- import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
5
-
6
- function toTwosComplement(num, bytesLen) {
7
- let maxValue = (1n << BigInt((bytesLen << 3)));
8
- let mask = maxValue - 1n;
9
- return num + maxValue & mask;
10
- }
11
-
12
- function fromSignedBigInt(val) {
13
- let val$1 = val >= 0n ? val : toTwosComplement(val, 32);
14
- return Viem.numberToHex(val$1, {
15
- size: 32
16
- });
17
- }
18
-
19
- function keccak256(prim) {
20
- return Viem.keccak256(prim);
21
- }
22
-
23
- function bytesToHex(prim0, prim1) {
24
- return Viem.bytesToHex(prim0, prim1 !== undefined ? Primitive_option.valFromOption(prim1) : undefined);
25
- }
26
-
27
- function concat(prim) {
28
- return Viem.concat(prim);
29
- }
30
-
31
- function castToHexUnsafe(val) {
32
- return val;
33
- }
34
-
35
- function fromBigInt(val) {
36
- return Viem.numberToHex(val, {
37
- size: 32
38
- });
39
- }
40
-
41
- function fromDynamicString(val) {
42
- return Viem.keccak256(val);
43
- }
44
-
45
- function fromString(val) {
46
- return Viem.stringToHex(val, {
47
- size: 32
48
- });
49
- }
50
4
 
51
5
  function fromAddress(addr) {
52
6
  return Viem.pad(addr);
53
7
  }
54
8
 
55
- function fromDynamicBytes(bytes) {
56
- return Viem.keccak256(bytes);
57
- }
58
-
59
- function fromBytes(bytes) {
60
- return Viem.bytesToHex(bytes, {
61
- size: 32
62
- });
63
- }
64
-
65
- function fromBool(b) {
66
- return Viem.boolToHex(b, {
67
- size: 32
68
- });
69
- }
70
-
71
9
  export {
72
- toTwosComplement,
73
- fromSignedBigInt,
74
- keccak256,
75
- bytesToHex,
76
- concat,
77
- castToHexUnsafe,
78
- fromBigInt,
79
- fromDynamicString,
80
- fromString,
81
10
  fromAddress,
82
- fromDynamicBytes,
83
- fromBytes,
84
- fromBool,
85
11
  }
86
12
  /* viem Not a pure module */