envio 3.5.0-alpha.1 → 3.5.0-alpha.2

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 (86) hide show
  1. package/index.d.ts +10 -6
  2. package/package.json +6 -6
  3. package/src/BatchProcessing.res +13 -0
  4. package/src/BatchProcessing.res.mjs +4 -0
  5. package/src/ChainFetching.res +5 -5
  6. package/src/ChainFetching.res.mjs +3 -4
  7. package/src/ChainState.res +38 -21
  8. package/src/ChainState.res.mjs +17 -24
  9. package/src/ChainState.resi +1 -5
  10. package/src/Change.res +3 -3
  11. package/src/Config.res +0 -4
  12. package/src/Config.res.mjs +0 -10
  13. package/src/Core.res +3 -0
  14. package/src/EntityId.res +15 -0
  15. package/src/EntityId.res.mjs +9 -0
  16. package/src/EventConfigBuilder.res +1 -58
  17. package/src/EventConfigBuilder.res.mjs +1 -33
  18. package/src/FetchState.res +345 -459
  19. package/src/FetchState.res.mjs +269 -430
  20. package/src/HandlerRegister.res +45 -0
  21. package/src/HandlerRegister.res.mjs +43 -0
  22. package/src/InMemoryStore.res +11 -4
  23. package/src/InMemoryTable.res +12 -10
  24. package/src/InMemoryTable.res.mjs +6 -5
  25. package/src/IndexerState.res +59 -2
  26. package/src/IndexerState.res.mjs +48 -3
  27. package/src/IndexerState.resi +2 -0
  28. package/src/Internal.res +17 -8
  29. package/src/LogSelection.res +2 -1
  30. package/src/Metrics.res +37 -6
  31. package/src/Metrics.res.mjs +5 -1
  32. package/src/Persistence.res +1 -1
  33. package/src/PgStorage.res +55 -22
  34. package/src/PgStorage.res.mjs +25 -17
  35. package/src/SimulateItems.res +2 -2
  36. package/src/TestIndexer.res +6 -5
  37. package/src/TestIndexer.res.mjs +3 -2
  38. package/src/UserContext.res +3 -3
  39. package/src/Writing.res +12 -2
  40. package/src/Writing.res.mjs +13 -2
  41. package/src/bindings/ClickHouse.res +5 -3
  42. package/src/bindings/ClickHouse.res.mjs +2 -5
  43. package/src/bindings/Vitest.res +22 -1
  44. package/src/bindings/Vitest.res.mjs +15 -0
  45. package/src/db/EntityHistory.res +16 -7
  46. package/src/db/EntityHistory.res.mjs +7 -6
  47. package/src/db/Table.res +40 -9
  48. package/src/db/Table.res.mjs +44 -6
  49. package/src/sources/AddressSet.res +48 -0
  50. package/src/sources/AddressSet.res.mjs +11 -0
  51. package/src/sources/AddressStore.res +152 -0
  52. package/src/sources/AddressStore.res.mjs +97 -0
  53. package/src/sources/EvmChain.res +3 -0
  54. package/src/sources/EvmChain.res.mjs +4 -2
  55. package/src/sources/EvmHyperSyncSource.res +6 -3
  56. package/src/sources/EvmHyperSyncSource.res.mjs +3 -3
  57. package/src/sources/EvmRpcClient.res +6 -3
  58. package/src/sources/EvmRpcClient.res.mjs +3 -3
  59. package/src/sources/FuelHyperSync.res +4 -3
  60. package/src/sources/FuelHyperSync.res.mjs +3 -3
  61. package/src/sources/FuelHyperSync.resi +2 -1
  62. package/src/sources/FuelHyperSyncClient.res +12 -6
  63. package/src/sources/FuelHyperSyncClient.res.mjs +2 -2
  64. package/src/sources/FuelHyperSyncSource.res +7 -4
  65. package/src/sources/FuelHyperSyncSource.res.mjs +3 -3
  66. package/src/sources/HyperSync.res +6 -4
  67. package/src/sources/HyperSync.res.mjs +2 -3
  68. package/src/sources/HyperSync.resi +1 -1
  69. package/src/sources/HyperSyncClient.res +18 -9
  70. package/src/sources/HyperSyncClient.res.mjs +4 -4
  71. package/src/sources/RpcSource.res +15 -10
  72. package/src/sources/RpcSource.res.mjs +3 -4
  73. package/src/sources/SimulateSource.res +26 -11
  74. package/src/sources/SimulateSource.res.mjs +13 -5
  75. package/src/sources/Source.res +4 -2
  76. package/src/sources/SourceManager.res +2 -3
  77. package/src/sources/SourceManager.res.mjs +2 -3
  78. package/src/sources/Svm.res +1 -2
  79. package/src/sources/Svm.res.mjs +1 -1
  80. package/src/sources/SvmHyperSyncClient.res +12 -3
  81. package/src/sources/SvmHyperSyncClient.res.mjs +2 -2
  82. package/src/sources/SvmHyperSyncSource.res +10 -5
  83. package/src/sources/SvmHyperSyncSource.res.mjs +5 -4
  84. package/src/IndexingAddresses.res +0 -151
  85. package/src/IndexingAddresses.res.mjs +0 -130
  86. package/src/IndexingAddresses.resi +0 -39
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
4
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
4
 
6
5
  function make(items, endBlock, chain) {
7
6
  let reportedHeight = Primitive_int.max(endBlock, 1);
@@ -22,7 +21,7 @@ function make(items, endBlock, chain) {
22
21
  height: reportedHeight,
23
22
  requestStats: []
24
23
  }),
25
- getItemsOrThrow: (fromBlock, toBlock, param, contractNameByAddress, param$1, param$2, selection, param$3, param$4, param$5) => {
24
+ getItemsOrThrow: (fromBlock, toBlock, addressSet, param, param$1, selection, param$2, param$3, param$4) => {
26
25
  let toBlockQueried = toBlock !== undefined ? toBlock : reportedHeight;
27
26
  let selectionEventIds = new Set();
28
27
  selection.onEventRegistrations.forEach(reg => {
@@ -37,11 +36,20 @@ function make(items, endBlock, chain) {
37
36
  if (!selectionEventIds.has(onEventRegistration.eventConfig.id)) {
38
37
  return false;
39
38
  }
40
- if (onEventRegistration.isWildcard) {
39
+ let contractName = onEventRegistration.eventConfig.contractName;
40
+ let emitterAllowed = onEventRegistration.isWildcard || addressSet.has(item.payload.srcAddress, contractName, blockNumber);
41
+ if (!emitterAllowed) {
42
+ return false;
43
+ }
44
+ let groups = onEventRegistration.addressFilterParamGroups;
45
+ if (groups === undefined) {
46
+ return true;
47
+ }
48
+ if (groups.length === 0) {
41
49
  return true;
42
50
  }
43
- let sa = item.payload.srcAddress;
44
- return Stdlib_Option.isSome(contractNameByAddress[sa]);
51
+ let params = item.payload.params;
52
+ return groups.some(group => group.every(name => addressSet.has(params[name], contractName, blockNumber)));
45
53
  });
46
54
  return Promise.resolve({
47
55
  knownHeight: reportedHeight,
@@ -73,8 +73,10 @@ type t = {
73
73
  getItemsOrThrow: (
74
74
  ~fromBlock: int,
75
75
  ~toBlock: option<int>,
76
- ~addressesByContractName: dict<array<Address.t>>,
77
- ~contractNameByAddress: dict<string>,
76
+ // The partition's slice of the chain's address index. The source hands it
77
+ // straight to its Rust client, which builds the query's address filter from
78
+ // it and gates every returned item against the chain-wide store.
79
+ ~addressSet: AddressSet.t,
78
80
  ~knownHeight: int,
79
81
  ~partitionId: string,
80
82
  ~selection: FetchState.selection,
@@ -754,7 +754,7 @@ let executeQuery = async (
754
754
  "source": source.name,
755
755
  "fromBlock": query.fromBlock,
756
756
  "toBlock": toBlock,
757
- "addresses": query.addressesByContractName->FetchState.addressesByContractNameCount,
757
+ "addresses": query.addresses->AddressSet.size,
758
758
  "retry": retry,
759
759
  },
760
760
  )
@@ -763,8 +763,7 @@ let executeQuery = async (
763
763
  let response = await source.getItemsOrThrow(
764
764
  ~fromBlock=query.fromBlock,
765
765
  ~toBlock,
766
- ~addressesByContractName=query.addressesByContractName,
767
- ~contractNameByAddress=query.addressesByContractName->FetchState.deriveContractNameByAddress,
766
+ ~addressSet=query.addresses,
768
767
  ~partitionId=query.partitionId,
769
768
  ~knownHeight,
770
769
  ~selection=query.selection,
@@ -3,7 +3,6 @@
3
3
  import * as Utils from "../Utils.res.mjs";
4
4
  import * as Source from "./Source.res.mjs";
5
5
  import * as Logging from "../Logging.res.mjs";
6
- import * as FetchState from "../FetchState.res.mjs";
7
6
  import * as Performance from "../bindings/Performance.res.mjs";
8
7
  import * as ErrorHandling from "../ErrorHandling.res.mjs";
9
8
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
@@ -597,11 +596,11 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
597
596
  source: source.name,
598
597
  fromBlock: query.fromBlock,
599
598
  toBlock: toBlock,
600
- addresses: FetchState.addressesByContractNameCount(query.addressesByContractName),
599
+ addresses: query.addresses.size(),
601
600
  retry: retry
602
601
  });
603
602
  try {
604
- let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addressesByContractName, FetchState.deriveContractNameByAddress(query.addressesByContractName), knownHeight, query.partitionId, query.selection, query.itemsTarget, retry, logger$2);
603
+ let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addresses, knownHeight, query.partitionId, query.selection, query.itemsTarget, retry, logger$2);
605
604
  recordRequestStats(sourceState, response.requestStats);
606
605
  sourceState.lastFailedAt = undefined;
607
606
  if (response.knownHeight > sourceState.knownHeight) {
@@ -100,8 +100,7 @@ let makeRPCSource = (~chain, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): S
100
100
  getItemsOrThrow: (
101
101
  ~fromBlock as _,
102
102
  ~toBlock as _,
103
- ~addressesByContractName as _,
104
- ~contractNameByAddress as _,
103
+ ~addressSet as _,
105
104
  ~knownHeight as _,
106
105
  ~partitionId as _,
107
106
  ~selection as _,
@@ -91,7 +91,7 @@ function makeRPCSource(chain, rpc, sourceForOpt) {
91
91
  }]
92
92
  };
93
93
  },
94
- getItemsOrThrow: (param, param$1, param$2, param$3, param$4, param$5, param$6, param$7, param$8, param$9) => Stdlib_JsError.throwWithMessage("Svm does not support getting items")
94
+ getItemsOrThrow: (param, param$1, param$2, param$3, param$4, param$5, param$6, param$7, param$8) => Stdlib_JsError.throwWithMessage("Svm does not support getting items")
95
95
  };
96
96
  }
97
97
 
@@ -191,7 +191,10 @@ module EventItems = {
191
191
  // Absent means no server-side cap on the number of instructions returned.
192
192
  maxNumInstructions?: int,
193
193
  registrationIndexes: array<int>,
194
- addressesByContractName: dict<array<Address.t>>,
194
+ // Program names to fetch address-free even though their registrations
195
+ // depend on addresses (client-side filtering). None/empty means every
196
+ // address-dependent program is filtered server-side.
197
+ clientFilteredContracts: option<array<string>>,
195
198
  }
196
199
 
197
200
  type log = {
@@ -221,8 +224,10 @@ module EventItems = {
221
224
 
222
225
  type response = {
223
226
  nextSlot: int,
224
- // One lean header per slot referenced by `items`; the full blocks live in
225
- // the block store returned alongside.
227
+ // One lean header per returned slot, including slots no item references
228
+ // reorg detection and the batch's latest timestamp read them all. The full
229
+ // blocks live in the block store returned alongside, which keeps only the
230
+ // slots items reference.
226
231
  blocks: array<ResponseTypes.block>,
227
232
  items: array<item>,
228
233
  }
@@ -240,6 +245,7 @@ type t = {
240
245
  // prep.
241
246
  getEventItems: (
242
247
  ~query: EventItems.query,
248
+ ~addressSet: AddressSet.t,
243
249
  ) => promise<(EventItems.response, TransactionStore.t, BlockStore.t)>,
244
250
  }
245
251
 
@@ -249,6 +255,7 @@ external classFromConfig: (
249
255
  cfg,
250
256
  string,
251
257
  array<Registration.input>,
258
+ AddressStore.t,
252
259
  ) => t = "fromConfig"
253
260
 
254
261
  let make = (
@@ -259,6 +266,7 @@ let make = (
259
266
  ~retryBaseMs=?,
260
267
  ~retryCeilingMs=?,
261
268
  ~eventRegistrations=[],
269
+ ~addressStore,
262
270
  ) => {
263
271
  let envioVersion = Utils.EnvioPackage.value.version
264
272
  Core.getAddon().svmHyperSyncClient->classFromConfig(
@@ -272,5 +280,6 @@ let make = (
272
280
  },
273
281
  `hyperindex/${envioVersion}`,
274
282
  eventRegistrations,
283
+ addressStore,
275
284
  )
276
285
  }
@@ -45,7 +45,7 @@ let ResponseTypes = {};
45
45
 
46
46
  let EventItems = {};
47
47
 
48
- function make(url, apiToken, httpReqTimeoutMillis, maxNumRetries, retryBaseMs, retryCeilingMs, eventRegistrationsOpt) {
48
+ function make(url, apiToken, httpReqTimeoutMillis, maxNumRetries, retryBaseMs, retryCeilingMs, eventRegistrationsOpt, addressStore) {
49
49
  let eventRegistrations = eventRegistrationsOpt !== undefined ? eventRegistrationsOpt : [];
50
50
  let envioVersion = Utils.EnvioPackage.value.version;
51
51
  return Core.getAddon().SvmHyperSyncClient.fromConfig({
@@ -55,7 +55,7 @@ function make(url, apiToken, httpReqTimeoutMillis, maxNumRetries, retryBaseMs, r
55
55
  maxNumRetries: maxNumRetries,
56
56
  retryBaseMs: retryBaseMs,
57
57
  retryCeilingMs: retryCeilingMs
58
- }, `hyperindex/` + envioVersion, eventRegistrations);
58
+ }, `hyperindex/` + envioVersion, eventRegistrations, addressStore);
59
59
  }
60
60
 
61
61
  export {
@@ -6,6 +6,8 @@ type options = {
6
6
  apiToken: option<string>,
7
7
  onEventRegistrations: array<Internal.svmOnEventRegistration>,
8
8
  clientTimeoutMillis: int,
9
+ // The chain's address index; the client reads it while routing.
10
+ addressStore: AddressStore.t,
9
11
  }
10
12
 
11
13
  // Synthesize a stable logIndex for an SVM instruction so the FetchState
@@ -66,7 +68,7 @@ let toSvmInstruction = (
66
68
  }
67
69
 
68
70
  let make = (
69
- {chain, endpointUrl, apiToken, onEventRegistrations, clientTimeoutMillis}: options,
71
+ {chain, endpointUrl, apiToken, onEventRegistrations, clientTimeoutMillis, addressStore}: options,
70
72
  ): t => {
71
73
  let name = "SvmHyperSync"
72
74
 
@@ -80,13 +82,13 @@ let make = (
80
82
  ~eventRegistrations=SvmHyperSyncClient.Registration.fromOnEventRegistrations(
81
83
  onEventRegistrations,
82
84
  ),
85
+ ~addressStore,
83
86
  )
84
87
 
85
88
  let getItemsOrThrow = async (
86
89
  ~fromBlock,
87
90
  ~toBlock,
88
- ~addressesByContractName,
89
- ~contractNameByAddress as _,
91
+ ~addressSet,
90
92
  ~knownHeight,
91
93
  ~partitionId as _,
92
94
  ~selection: FetchState.selection,
@@ -102,10 +104,13 @@ let make = (
102
104
  toSlot: toBlock,
103
105
  maxNumInstructions: ?itemsTarget,
104
106
  registrationIndexes: selection.onEventRegistrations->Array.map(reg => reg.index),
105
- addressesByContractName,
107
+ clientFilteredContracts: selection.clientFilteredContracts,
106
108
  }
107
109
 
108
- let (resp, transactionStore, blockStore) = try await client.getEventItems(~query) catch {
110
+ let (resp, transactionStore, blockStore) = try await client.getEventItems(
111
+ ~query,
112
+ ~addressSet,
113
+ ) catch {
109
114
  | exn =>
110
115
  throw(
111
116
  Source.GetItemsError(
@@ -58,21 +58,22 @@ function toSvmInstruction(item, programName, instructionName) {
58
58
  function make(param) {
59
59
  let onEventRegistrations = param.onEventRegistrations;
60
60
  let chain = param.chain;
61
- let client = SvmHyperSyncClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, undefined, undefined, undefined, SvmHyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations));
62
- let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, param, knownHeight, param$1, selection, itemsTarget, retry, param$2) => {
61
+ let client = SvmHyperSyncClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, undefined, undefined, undefined, SvmHyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations), param.addressStore);
62
+ let getItemsOrThrow = async (fromBlock, toBlock, addressSet, knownHeight, param, selection, itemsTarget, retry, param$1) => {
63
63
  let totalTimeRef = Performance.now();
64
64
  let pageFetchRef = Performance.now();
65
65
  let query_registrationIndexes = selection.onEventRegistrations.map(reg => reg.index);
66
+ let query_clientFilteredContracts = selection.clientFilteredContracts;
66
67
  let query = {
67
68
  fromSlot: fromBlock,
68
69
  toSlot: toBlock,
69
70
  maxNumInstructions: itemsTarget,
70
71
  registrationIndexes: query_registrationIndexes,
71
- addressesByContractName: addressesByContractName
72
+ clientFilteredContracts: query_clientFilteredContracts
72
73
  };
73
74
  let match;
74
75
  try {
75
- match = await client.getEventItems(query);
76
+ match = await client.getEventItems(query, addressSet);
76
77
  } catch (raw_exn) {
77
78
  let exn = Primitive_exceptions.internalToException(raw_exn);
78
79
  throw {
@@ -1,151 +0,0 @@
1
- type indexingAddress = Internal.indexingContract
2
-
3
- type contractConfig = {startBlock: option<int>}
4
-
5
- // Grouped by contract name, then by address string. Contracts are few, so
6
- // per-contract operations (address count, the client-side filter's lookup
7
- // dict) are direct, and whole-index scans (get by address, rollback) walk the
8
- // small contract set. Address strings are globally unique across contracts
9
- // (conflicting registrations are rejected before they reach here).
10
- type t = dict<dict<indexingAddress>>
11
-
12
- let deriveEffectiveStartBlock = (~registrationBlock: int, ~contractStartBlock: option<int>) => {
13
- Pervasives.max(Pervasives.max(registrationBlock, 0), contractStartBlock->Option.getOr(0))
14
- }
15
-
16
- let makeContractConfigs = (~onEventRegistrations: array<Internal.onEventRegistration>): dict<
17
- contractConfig,
18
- > => {
19
- let contractConfigs: dict<contractConfig> = Dict.make()
20
- onEventRegistrations->Array.forEach(reg => {
21
- let contractName = reg.eventConfig.contractName
22
- switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(contractName) {
23
- | Some({startBlock}) =>
24
- contractConfigs->Dict.set(
25
- contractName,
26
- {
27
- startBlock: switch (startBlock, reg.startBlock) {
28
- | (Some(a), Some(b)) => Some(Pervasives.min(a, b))
29
- | (Some(_) as s, None) | (None, Some(_) as s) => s
30
- | (None, None) => None
31
- },
32
- },
33
- )
34
- | None =>
35
- contractConfigs->Dict.set(
36
- contractName,
37
- {
38
- startBlock: reg.startBlock,
39
- },
40
- )
41
- }
42
- })
43
- contractConfigs
44
- }
45
-
46
- let makeIndexingAddress = (
47
- ~contract: Internal.indexingAddress,
48
- ~contractConfigs: dict<contractConfig>,
49
- ): indexingAddress => {
50
- let contractStartBlock = switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(
51
- contract.contractName,
52
- ) {
53
- | Some({startBlock}) => startBlock
54
- | None => None
55
- }
56
- {
57
- address: contract.address,
58
- contractName: contract.contractName,
59
- registrationBlock: contract.registrationBlock,
60
- effectiveStartBlock: deriveEffectiveStartBlock(
61
- ~registrationBlock=contract.registrationBlock,
62
- ~contractStartBlock,
63
- ),
64
- }
65
- }
66
-
67
- let insert = (indexingAddresses: t, indexingAddress: indexingAddress) => {
68
- indexingAddresses
69
- ->Utils.Dict.getOrInsertEmptyDict(indexingAddress.contractName)
70
- ->Dict.set(indexingAddress.address->Address.toString, indexingAddress)
71
- }
72
-
73
- let make = (
74
- ~contractConfigs: dict<contractConfig>,
75
- ~addresses: array<Internal.indexingAddress>,
76
- ): t => {
77
- let indexingAddresses = Dict.make()
78
- addresses->Array.forEach(contract => {
79
- indexingAddresses->insert(makeIndexingAddress(~contract, ~contractConfigs))
80
- })
81
- indexingAddresses
82
- }
83
-
84
- // Address strings are globally unique, so the first inner dict holding the
85
- // address owns it. for..in returns on the first hit without allocating a values
86
- // array per lookup (get runs once per registration).
87
- let get: (t, string) => option<indexingAddress> = %raw(`(index, address) => {
88
- for (var contractName in index) {
89
- var entry = index[contractName][address];
90
- if (entry !== undefined) {
91
- return entry;
92
- }
93
- }
94
- return undefined;
95
- }`)
96
-
97
- let size = (indexingAddresses: t) => {
98
- let total = ref(0)
99
- indexingAddresses->Utils.Dict.forEach(inner => {
100
- total := total.contents + inner->Utils.Dict.size
101
- })
102
- total.contents
103
- }
104
-
105
- // Number of registered addresses for a single contract — a for..in over that
106
- // one contract's addresses. The trigger deciding when to switch a contract to
107
- // client-side filtering reads this.
108
- let contractCount = (indexingAddresses: t, ~contractName) =>
109
- switch indexingAddresses->Utils.Dict.dangerouslyGetNonOption(contractName) {
110
- | Some(inner) => inner->Utils.Dict.size
111
- | None => 0
112
- }
113
-
114
- let getContractAddresses = (indexingAddresses: t, ~contractName): array<Address.t> => {
115
- switch indexingAddresses->Utils.Dict.dangerouslyGetNonOption(contractName) {
116
- | Some(inner) => inner->Dict.valuesToArray->Array.map(ia => ia.address)
117
- | None => []
118
- }
119
- }
120
-
121
- let emptyContractDict: dict<indexingAddress> = Dict.make()
122
-
123
- // The address→entry dict for a single contract, passed to that contract's
124
- // precompiled `clientAddressFilter` (which does raw `byAddr[srcAddress]` access
125
- // in generated JS). Every leaf of a filter references the event's own contract
126
- // — `chain.<Contract>.addresses` only exposes the event's contract — so one
127
- // inner dict covers the srcAddress and param-address checks alike. Returns a
128
- // shared empty dict when the contract has no registered addresses.
129
- let forContract = (indexingAddresses: t, ~contractName): dict<indexingAddress> =>
130
- switch indexingAddresses->Utils.Dict.dangerouslyGetNonOption(contractName) {
131
- | Some(inner) => inner
132
- | None => emptyContractDict
133
- }
134
-
135
- let register = (indexingAddresses: t, additions: dict<indexingAddress>) => {
136
- additions->Utils.Dict.forEach(indexingAddress => {
137
- indexingAddresses->insert(indexingAddress)
138
- })
139
- }
140
-
141
- let rollbackInPlace = (indexingAddresses: t, ~targetBlockNumber: int): unit => {
142
- // forEachWithKey is a `for..in`, so deleting the key currently being visited is
143
- // safe — it doesn't affect enumeration of the remaining keys.
144
- indexingAddresses->Utils.Dict.forEach(inner => {
145
- inner->Utils.Dict.forEachWithKey((indexingContract, address) => {
146
- if indexingContract.registrationBlock > targetBlockNumber {
147
- inner->Utils.Dict.deleteInPlace(address)
148
- }
149
- })
150
- })
151
- }
@@ -1,130 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Utils from "./Utils.res.mjs";
4
- import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
5
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
-
7
- function deriveEffectiveStartBlock(registrationBlock, contractStartBlock) {
8
- return Primitive_int.max(Primitive_int.max(registrationBlock, 0), Stdlib_Option.getOr(contractStartBlock, 0));
9
- }
10
-
11
- function makeContractConfigs(onEventRegistrations) {
12
- let contractConfigs = {};
13
- onEventRegistrations.forEach(reg => {
14
- let contractName = reg.eventConfig.contractName;
15
- let match = contractConfigs[contractName];
16
- if (match !== undefined) {
17
- let startBlock = match.startBlock;
18
- let match$1 = reg.startBlock;
19
- contractConfigs[contractName] = {
20
- startBlock: startBlock !== undefined ? (
21
- match$1 !== undefined ? Primitive_int.min(startBlock, match$1) : startBlock
22
- ) : (
23
- match$1 !== undefined ? match$1 : undefined
24
- )
25
- };
26
- return;
27
- }
28
- contractConfigs[contractName] = {
29
- startBlock: reg.startBlock
30
- };
31
- });
32
- return contractConfigs;
33
- }
34
-
35
- function makeIndexingAddress(contract, contractConfigs) {
36
- let match = contractConfigs[contract.contractName];
37
- let contractStartBlock = match !== undefined ? match.startBlock : undefined;
38
- return {
39
- address: contract.address,
40
- contractName: contract.contractName,
41
- registrationBlock: contract.registrationBlock,
42
- effectiveStartBlock: deriveEffectiveStartBlock(contract.registrationBlock, contractStartBlock)
43
- };
44
- }
45
-
46
- function insert(indexingAddresses, indexingAddress) {
47
- Utils.Dict.getOrInsertEmptyDict(indexingAddresses, indexingAddress.contractName)[indexingAddress.address] = indexingAddress;
48
- }
49
-
50
- function make(contractConfigs, addresses) {
51
- let indexingAddresses = {};
52
- addresses.forEach(contract => insert(indexingAddresses, makeIndexingAddress(contract, contractConfigs)));
53
- return indexingAddresses;
54
- }
55
-
56
- let get = ((index, address) => {
57
- for (var contractName in index) {
58
- var entry = index[contractName][address];
59
- if (entry !== undefined) {
60
- return entry;
61
- }
62
- }
63
- return undefined;
64
- });
65
-
66
- function size(indexingAddresses) {
67
- let total = {
68
- contents: 0
69
- };
70
- Utils.Dict.forEach(indexingAddresses, inner => {
71
- total.contents = total.contents + Utils.Dict.size(inner) | 0;
72
- });
73
- return total.contents;
74
- }
75
-
76
- function contractCount(indexingAddresses, contractName) {
77
- let inner = indexingAddresses[contractName];
78
- if (inner !== undefined) {
79
- return Utils.Dict.size(inner);
80
- } else {
81
- return 0;
82
- }
83
- }
84
-
85
- function getContractAddresses(indexingAddresses, contractName) {
86
- let inner = indexingAddresses[contractName];
87
- if (inner !== undefined) {
88
- return Object.values(inner).map(ia => ia.address);
89
- } else {
90
- return [];
91
- }
92
- }
93
-
94
- let emptyContractDict = {};
95
-
96
- function forContract(indexingAddresses, contractName) {
97
- let inner = indexingAddresses[contractName];
98
- if (inner !== undefined) {
99
- return inner;
100
- } else {
101
- return emptyContractDict;
102
- }
103
- }
104
-
105
- function register(indexingAddresses, additions) {
106
- Utils.Dict.forEach(additions, indexingAddress => insert(indexingAddresses, indexingAddress));
107
- }
108
-
109
- function rollbackInPlace(indexingAddresses, targetBlockNumber) {
110
- Utils.Dict.forEach(indexingAddresses, inner => Utils.Dict.forEachWithKey(inner, (indexingContract, address) => {
111
- if (indexingContract.registrationBlock > targetBlockNumber) {
112
- return Utils.Dict.deleteInPlace(inner, address);
113
- }
114
- }));
115
- }
116
-
117
- export {
118
- deriveEffectiveStartBlock,
119
- makeContractConfigs,
120
- makeIndexingAddress,
121
- make,
122
- get,
123
- size,
124
- contractCount,
125
- getContractAddresses,
126
- forContract,
127
- register,
128
- rollbackInPlace,
129
- }
130
- /* Utils Not a pure module */
@@ -1,39 +0,0 @@
1
- type indexingAddress = Internal.indexingContract
2
-
3
- type contractConfig = {startBlock: option<int>}
4
-
5
- type t
6
-
7
- let deriveEffectiveStartBlock: (~registrationBlock: int, ~contractStartBlock: option<int>) => int
8
-
9
- let makeContractConfigs: (
10
- ~onEventRegistrations: array<Internal.onEventRegistration>,
11
- ) => dict<contractConfig>
12
-
13
- let makeIndexingAddress: (
14
- ~contract: Internal.indexingAddress,
15
- ~contractConfigs: dict<contractConfig>,
16
- ) => indexingAddress
17
-
18
- let make: (~contractConfigs: dict<contractConfig>, ~addresses: array<Internal.indexingAddress>) => t
19
-
20
- let get: (t, string) => option<indexingAddress>
21
-
22
- let size: t => int
23
-
24
- // Number of registered addresses for a single contract (scans just that
25
- // contract's addresses).
26
- let contractCount: (t, ~contractName: string) => int
27
-
28
- let getContractAddresses: (t, ~contractName: string) => array<Address.t>
29
-
30
- // The address→entry dict for a single contract, passed to that contract's
31
- // precompiled `clientAddressFilter` (raw `byAddr[srcAddress]` access in
32
- // generated JS). Don't use elsewhere — prefer the domain accessors so the
33
- // opaque type stays enforced.
34
- let forContract: (t, ~contractName: string) => dict<indexingAddress>
35
-
36
- let register: (t, dict<indexingAddress>) => unit
37
-
38
- // Deletes addresses registered after `targetBlockNumber` from the index in place.
39
- let rollbackInPlace: (t, ~targetBlockNumber: int) => unit