envio 3.15.0 → 3.16.0-subgraph

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 (186) hide show
  1. package/README.md +40 -34
  2. package/evm.schema.json +11 -2
  3. package/fuel.schema.json +10 -1
  4. package/index.d.ts +6 -0
  5. package/licenses/README.md +1 -1
  6. package/package.json +10 -9
  7. package/src/Batch.res.mjs +5 -5
  8. package/src/BatchProcessing.res +1 -0
  9. package/src/BatchProcessing.res.mjs +1 -0
  10. package/src/Bin.res +7 -0
  11. package/src/Bin.res.mjs +8 -0
  12. package/src/ChainFetching.res +450 -16
  13. package/src/ChainFetching.res.mjs +403 -32
  14. package/src/ChainState.res +124 -7
  15. package/src/ChainState.res.mjs +128 -67
  16. package/src/ChainState.resi +26 -0
  17. package/src/Clock.res +57 -0
  18. package/src/Clock.res.mjs +72 -0
  19. package/src/Config.res +31 -3
  20. package/src/Config.res.mjs +15 -4
  21. package/src/ContractRegisterContext.res +3 -6
  22. package/src/ContractRegisterContext.res.mjs +4 -2
  23. package/src/Core.res +95 -36
  24. package/src/Core.res.mjs +90 -1
  25. package/src/CrossChainState.res +12 -2
  26. package/src/CrossChainState.res.mjs +3 -3
  27. package/src/Ecosystem.res +7 -4
  28. package/src/Ecosystem.res.mjs +8 -8
  29. package/src/EffectCacheLookup.res +98 -0
  30. package/src/EffectCacheLookup.res.mjs +116 -0
  31. package/src/EffectState.res +10 -2
  32. package/src/EffectState.res.mjs +8 -4
  33. package/src/EffectState.resi +3 -1
  34. package/src/EntityId.res +2 -7
  35. package/src/EntityId.res.mjs +1 -8
  36. package/src/EntityTables.res +4 -1
  37. package/src/EntityTables.res.mjs +1 -1
  38. package/src/Env.res +20 -0
  39. package/src/Env.res.mjs +16 -0
  40. package/src/EventProcessing.res +38 -1
  41. package/src/EventProcessing.res.mjs +28 -1
  42. package/src/FetchState.res +408 -73
  43. package/src/FetchState.res.mjs +361 -91
  44. package/src/FinalizeBackfill.res +2 -4
  45. package/src/FinalizeBackfill.res.mjs +3 -4
  46. package/src/HandlerLoader.res +39 -15
  47. package/src/HandlerLoader.res.mjs +27 -8
  48. package/src/HandlerRegister.res +4 -0
  49. package/src/HandlerRegister.res.mjs +5 -2
  50. package/src/HandlerRegister.resi +2 -0
  51. package/src/InMemoryTable.res +17 -16
  52. package/src/InMemoryTable.res.mjs +14 -15
  53. package/src/IndexerState.res +28 -4
  54. package/src/IndexerState.res.mjs +19 -6
  55. package/src/IndexerState.resi +4 -0
  56. package/src/Internal.res +61 -49
  57. package/src/Internal.res.mjs +36 -80
  58. package/src/LoadLayer.res +54 -15
  59. package/src/LoadLayer.res.mjs +75 -45
  60. package/src/LoadLayer.resi +26 -0
  61. package/src/Main.res +14 -1
  62. package/src/Main.res.mjs +4 -3
  63. package/src/Persistence.res +3 -23
  64. package/src/Persistence.res.mjs +3 -3
  65. package/src/PreloadLookahead.res +202 -0
  66. package/src/PreloadLookahead.res.mjs +218 -0
  67. package/src/Rollback.res +0 -1
  68. package/src/Rollback.res.mjs +1 -1
  69. package/src/RunScope.res +3 -0
  70. package/src/SafeCheckpointTracking.res +4 -4
  71. package/src/SafeCheckpointTracking.res.mjs +1 -1
  72. package/src/SimulateItems.res +42 -26
  73. package/src/SimulateItems.res.mjs +40 -16
  74. package/src/StagedRows.res +106 -0
  75. package/src/StagedRows.res.mjs +102 -0
  76. package/src/Staging.res +32 -14
  77. package/src/Staging.res.mjs +17 -20
  78. package/src/Storage.res +303 -948
  79. package/src/Storage.res.mjs +229 -708
  80. package/src/SubgraphLog.res +19 -0
  81. package/src/SubgraphLog.res.mjs +26 -0
  82. package/src/Supervisor.res +75 -56
  83. package/src/Supervisor.res.mjs +55 -26
  84. package/src/SyncWrites.res +107 -0
  85. package/src/SyncWrites.res.mjs +98 -0
  86. package/src/TestIndexer.res +22 -27
  87. package/src/TestIndexer.res.mjs +20 -17
  88. package/src/Throttler.res +15 -8
  89. package/src/Throttler.res.mjs +9 -6
  90. package/src/Throttler.resi +1 -1
  91. package/src/UserContext.res +419 -46
  92. package/src/UserContext.res.mjs +318 -30
  93. package/src/Utils.res +17 -6
  94. package/src/Utils.res.mjs +12 -6
  95. package/src/Writing.res +0 -1
  96. package/src/Writing.res.mjs +1 -1
  97. package/src/bindings/ClickHouse.res +0 -322
  98. package/src/bindings/ClickHouse.res.mjs +0 -338
  99. package/src/bindings/StorageClient.res +108 -174
  100. package/src/bindings/StorageClient.res.mjs +19 -8
  101. package/src/bindings/Vitest.res +0 -26
  102. package/src/bindings/Vitest.res.mjs +0 -3
  103. package/src/db/Table.res +24 -150
  104. package/src/db/Table.res.mjs +38 -272
  105. package/src/sources/AddressSet.res +2 -0
  106. package/src/sources/AddressStore.res +3 -0
  107. package/src/sources/CallSource.res +274 -0
  108. package/src/sources/CallSource.res.mjs +196 -0
  109. package/src/sources/ChainSources.res +2 -0
  110. package/src/sources/ChainSources.res.mjs +2 -2
  111. package/src/sources/EvmChain.res +10 -1
  112. package/src/sources/EvmChain.res.mjs +6 -3
  113. package/src/sources/EvmHyperSyncSource.res +2 -2
  114. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  115. package/src/sources/EvmRpcClient.res +13 -3
  116. package/src/sources/EvmRpcClient.res.mjs +4 -3
  117. package/src/sources/EvmRpcWs.res +4 -3
  118. package/src/sources/EvmRpcWs.res.mjs +2 -2
  119. package/src/sources/HeightFeed.res +31 -10
  120. package/src/sources/HeightFeed.res.mjs +10 -6
  121. package/src/sources/HeightStream.res +32 -17
  122. package/src/sources/HeightStream.res.mjs +10 -10
  123. package/src/sources/HyperSync.res +2 -1
  124. package/src/sources/HyperSync.res.mjs +2 -1
  125. package/src/sources/HyperSyncSSE.res +4 -6
  126. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  127. package/src/sources/RpcSource.res +10 -1
  128. package/src/sources/RpcSource.res.mjs +4 -3
  129. package/src/sources/Source.res +3 -0
  130. package/src/sources/SourceManager.res +84 -77
  131. package/src/sources/SourceManager.res.mjs +17 -20
  132. package/src/sources/SourceManager.resi +3 -4
  133. package/src/sources/StartBlockResolver.res +1 -0
  134. package/src/sources/StartBlockResolver.res.mjs +3 -2
  135. package/src/sources/SvmHyperSyncSource.res +2 -2
  136. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  137. package/src/subgraph/abi-types.ts +84 -0
  138. package/src/subgraph/aggregations.ts +745 -0
  139. package/src/subgraph/as-package.ts +143 -0
  140. package/src/subgraph/assemblyscript-regex.ts +67 -0
  141. package/src/subgraph/assemblyscript.ts +731 -0
  142. package/src/subgraph/blocks.ts +398 -0
  143. package/src/subgraph/calls-source.ts +702 -0
  144. package/src/subgraph/calls.ts +258 -0
  145. package/src/subgraph/conformance.ts +106 -0
  146. package/src/subgraph/errors.ts +85 -0
  147. package/src/subgraph/graft.ts +73 -0
  148. package/src/subgraph/graph-cli-worker.mjs +35 -0
  149. package/src/subgraph/graph-cli.ts +900 -0
  150. package/src/subgraph/graph-node-decimal.ts +199 -0
  151. package/src/subgraph/graph-ts-enums.ts +28 -0
  152. package/src/subgraph/graph-ts-types/VERSION +2 -0
  153. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
  154. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
  155. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
  156. package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
  157. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
  158. package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
  159. package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
  160. package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
  161. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  162. package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
  163. package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
  164. package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
  165. package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
  166. package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
  167. package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
  168. package/src/subgraph/graph-ts-types/index.d.ts +102 -0
  169. package/src/subgraph/graph-ts.ts +4339 -0
  170. package/src/subgraph/hosts.ts +554 -0
  171. package/src/subgraph/log.ts +28 -0
  172. package/src/subgraph/receipts.ts +184 -0
  173. package/src/subgraph/register-slots.ts +93 -0
  174. package/src/subgraph/rollup.ts +109 -0
  175. package/src/subgraph/rpc.ts +337 -0
  176. package/src/subgraph/runtime.ts +2059 -0
  177. package/src/subgraph/scope.ts +176 -0
  178. package/src/subgraph/stats.ts +42 -0
  179. package/src/subgraph/template-instances.ts +66 -0
  180. package/src/subgraph/toolchain.ts +327 -0
  181. package/src/subgraph/transient.ts +176 -0
  182. package/svm.schema.json +11 -2
  183. package/src/PgWriting.res +0 -36
  184. package/src/PgWriting.res.mjs +0 -34
  185. package/src/db/IndexDefinition.res +0 -47
  186. package/src/db/IndexDefinition.res.mjs +0 -67
@@ -0,0 +1,274 @@
1
+ // Subgraph mode only. A subgraph's call handlers run on calls, which a log
2
+ // source never sees, so each source of a chain is wrapped: it fetches the logs
3
+ // of a query as before, and the calls of the same block range from a trace
4
+ // backend (`subgraph/calls-source.ts`). A call comes back as the event item it
5
+ // travels as for the rest of envio — partitioning, ordering, the register
6
+ // pass and rollback never tell it from a log.
7
+
8
+ type callRegistration = {
9
+ index: int,
10
+ contractName: string,
11
+ eventName: string,
12
+ selector: Nullable.t<string>,
13
+ rank: int,
14
+ isWildcard: bool,
15
+ startBlock: Nullable.t<int>,
16
+ }
17
+
18
+ type request = {
19
+ chainId: ChainId.t,
20
+ fromBlock: int,
21
+ toBlock: int,
22
+ registrations: array<callRegistration>,
23
+ addresses: dict<array<string>>,
24
+ rpcUrls: array<string>,
25
+ }
26
+
27
+ type callItem = {
28
+ registrationIndex: int,
29
+ blockNumber: int,
30
+ transactionIndex: int,
31
+ traceAddress: array<int>,
32
+ payload: Internal.eventPayload,
33
+ }
34
+
35
+ type response = {
36
+ items: array<callItem>,
37
+ latestFetchedBlockNumber: int,
38
+ blocks: array<BlockStore.inputBlock>,
39
+ knownHeight: Nullable.t<int>,
40
+ }
41
+
42
+ type installed = {
43
+ fetchCalls: request => promise<response>,
44
+ rpcUrls: array<string>,
45
+ }
46
+
47
+ let installed: ref<option<installed>> = ref(None)
48
+
49
+ let install = (~fetchCalls, ~rpcUrls) => {
50
+ installed := Some({fetchCalls, rpcUrls})
51
+ }
52
+
53
+ // The block range one call query covers when the partition's own is open-ended.
54
+ let openEndedSpan = 1_000_000
55
+
56
+ let callRankOf = (registration: Internal.onEventRegistration) =>
57
+ Internal.callRankOfEventName(registration.eventConfig.name)
58
+
59
+ // `__envio_call_<8 hex digits>_<function>`
60
+ let selectorOf = (registration: Internal.onEventRegistration) =>
61
+ switch registration->callRankOf {
62
+ | Some(1) =>
63
+ Nullable.Value(
64
+ "0x" ++ registration.eventConfig.name->String.slice(~start=13, ~end=21)->String.toLowerCase,
65
+ )
66
+ | _ => Nullable.null
67
+ }
68
+
69
+ let wrap = (
70
+ source: Source.t,
71
+ ~addressStore: AddressStore.t,
72
+ ~ecosystem: Ecosystem.name,
73
+ installed: installed,
74
+ ): Source.t => {
75
+ ...source,
76
+ getItemsOrThrow: async (
77
+ ~fromBlock,
78
+ ~toBlock,
79
+ ~addressSet,
80
+ ~reorgableFrom,
81
+ ~knownHeight,
82
+ ~partitionId,
83
+ ~selection: FetchState.selection,
84
+ ~itemsTarget,
85
+ ~retry,
86
+ ~logger,
87
+ ) => {
88
+ let callRegistrations =
89
+ selection.onEventRegistrations->Array.filter(registration =>
90
+ registration->callRankOf->Option.isSome
91
+ )
92
+ if callRegistrations->Utils.Array.isEmpty {
93
+ await source.getItemsOrThrow(
94
+ ~fromBlock,
95
+ ~toBlock,
96
+ ~addressSet,
97
+ ~reorgableFrom,
98
+ ~knownHeight,
99
+ ~partitionId,
100
+ ~selection,
101
+ ~itemsTarget,
102
+ ~retry,
103
+ ~logger,
104
+ )
105
+ } else {
106
+ let logRegistrations =
107
+ selection.onEventRegistrations->Array.filter(registration =>
108
+ registration->callRankOf->Option.isNone
109
+ )
110
+ let logs = if (
111
+ logRegistrations->Utils.Array.isEmpty && selection.onBlockRegistrations->Utils.Array.isEmpty
112
+ ) {
113
+ None
114
+ } else {
115
+ Some(
116
+ await source.getItemsOrThrow(
117
+ ~fromBlock,
118
+ ~toBlock,
119
+ ~addressSet,
120
+ ~reorgableFrom,
121
+ ~knownHeight,
122
+ ~partitionId,
123
+ ~selection={...selection, onEventRegistrations: logRegistrations},
124
+ ~itemsTarget,
125
+ ~retry,
126
+ ~logger,
127
+ ),
128
+ )
129
+ }
130
+
131
+ // Calls are asked for only as far as the logs were: a source may stop a
132
+ // page short, and the two have to agree on where the answer ends.
133
+ let rangeEnd = switch (logs, toBlock) {
134
+ | (Some(logs), _) => logs.latestFetchedBlockNumber
135
+ | (None, Some(toBlock)) => toBlock
136
+ | (None, None) => Math.Int.min(knownHeight, fromBlock + openEndedSpan)
137
+ }
138
+
139
+ let clientFiltered = contractName =>
140
+ switch selection.clientFilteredContracts {
141
+ | Some(contractNames) => contractNames->Array.includes(contractName)
142
+ | None => false
143
+ }
144
+ let addresses = Dict.make()
145
+ callRegistrations->Array.forEach(registration => {
146
+ let contractName = registration.eventConfig.contractName
147
+ if !registration.isWildcard && addresses->Dict.get(contractName)->Option.isNone {
148
+ addresses->Dict.set(
149
+ contractName,
150
+ clientFiltered(contractName)
151
+ ? addressStore->AddressStore.contractAddresses(contractName, ~shouldChecksum=false)
152
+ : addressSet->AddressSet.addressesOf(contractName),
153
+ )
154
+ }
155
+ })
156
+
157
+ let startedAt = Performance.now()
158
+ let response = try await installed.fetchCalls({
159
+ chainId: source.chainId,
160
+ fromBlock,
161
+ toBlock: rangeEnd,
162
+ registrations: callRegistrations->Array.map(registration => {
163
+ index: registration.index,
164
+ contractName: registration.eventConfig.contractName,
165
+ eventName: registration.eventConfig.name,
166
+ selector: registration->selectorOf,
167
+ rank: registration->callRankOf->Option.getOr(1),
168
+ isWildcard: registration.isWildcard,
169
+ startBlock: registration.startBlock->Nullable.fromOption,
170
+ }),
171
+ addresses: addresses->(Utils.magic: dict<array<Address.t>> => dict<array<string>>),
172
+ rpcUrls: installed.rpcUrls,
173
+ }) catch {
174
+ | exn =>
175
+ throw(
176
+ Source.GetItemsError(
177
+ Source.FailedGettingItems({
178
+ exn,
179
+ attemptedToBlock: rangeEnd,
180
+ retry: WithBackoff({
181
+ message: `Failed reading the calls of blocks ${fromBlock->Int.toString} to ${rangeEnd->Int.toString}. Attempt a retry.`,
182
+ backoffMillis: switch retry {
183
+ | 0 => 500
184
+ | _ => 1000 * retry
185
+ },
186
+ }),
187
+ requestStats: [],
188
+ }),
189
+ ),
190
+ )
191
+ }
192
+ let callSeconds = startedAt->Performance.secondsSince
193
+
194
+ let registrationByIndex = Dict.make()
195
+ callRegistrations->Array.forEach(registration =>
196
+ registrationByIndex->Dict.set(registration.index->Int.toString, registration)
197
+ )
198
+ let latest = response.latestFetchedBlockNumber
199
+ let callItems = response.items->Array.filterMap(callItem => {
200
+ let registration =
201
+ registrationByIndex->Dict.getUnsafe(callItem.registrationIndex->Int.toString)
202
+ let contractName = registration.eventConfig.contractName
203
+ // The partition's own slice of the contract's addresses, as a log's
204
+ // router applies it; a client-filtered contract answers to the store.
205
+ let ownsCall =
206
+ registration.isWildcard || {
207
+ let address = callItem.payload->Internal.getPayloadSrcAddress
208
+ if clientFiltered(contractName) {
209
+ addressStore->AddressStore.isIndexedAt(address, contractName, callItem.blockNumber)
210
+ } else {
211
+ addressSet->AddressSet.containsAt(address, contractName, callItem.blockNumber)
212
+ }
213
+ }
214
+ if callItem.blockNumber <= latest && ownsCall {
215
+ let item = Internal.Event({
216
+ onEventRegistration: registration,
217
+ chainId: source.chainId,
218
+ blockNumber: callItem.blockNumber,
219
+ logIndex: 0,
220
+ orderPath: callItem.traceAddress,
221
+ transactionIndex: callItem.transactionIndex,
222
+ payload: callItem.payload,
223
+ })
224
+ item->Internal.markItemCall(~rank=registration->callRankOf->Option.getOr(1))
225
+ Some(item)
226
+ } else {
227
+ None
228
+ }
229
+ })
230
+
231
+ let callBlocks = BlockStore.fromJs(response.blocks, ~ecosystem)
232
+ let callRequestStat = {Source.method: "getCalls", seconds: callSeconds}
233
+ switch logs {
234
+ | Some(logs) =>
235
+ logs.blockStore->BlockStore.appendPage(callBlocks)
236
+ {
237
+ ...logs,
238
+ parsedQueueItems: Array.concat(
239
+ logs.parsedQueueItems->Array.filter(item =>
240
+ item->Internal.getItemBlockNumber <= latest
241
+ ),
242
+ callItems,
243
+ ),
244
+ latestFetchedBlockNumber: Math.Int.min(logs.latestFetchedBlockNumber, latest),
245
+ requestStats: Array.concat(logs.requestStats, [callRequestStat]),
246
+ }
247
+ | None => {
248
+ Source.knownHeight: response.knownHeight->Nullable.getOr(knownHeight),
249
+ parsedQueueItems: callItems,
250
+ transactionStore: None,
251
+ blockStore: callBlocks,
252
+ latestFetchedBlockNumber: latest,
253
+ stats: {totalTimeElapsed: callSeconds},
254
+ requestStats: [callRequestStat],
255
+ }
256
+ }
257
+ }
258
+ },
259
+ }
260
+
261
+ // Wraps every source of a chain when its registrations hold a call trigger
262
+ // and the subgraph runtime has installed the backend that reads them.
263
+ let wrapSources = (
264
+ sources: array<Source.t>,
265
+ ~onEventRegistrations: array<Internal.onEventRegistration>,
266
+ ~addressStore,
267
+ ~ecosystem,
268
+ ) =>
269
+ switch installed.contents {
270
+ | Some(installed)
271
+ if onEventRegistrations->Array.some(registration => registration->callRankOf->Option.isSome) =>
272
+ sources->Array.map(source => source->wrap(~addressStore, ~ecosystem, installed))
273
+ | _ => sources
274
+ }
@@ -0,0 +1,196 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "../Utils.res.mjs";
4
+ import * as Source from "./Source.res.mjs";
5
+ import * as Internal from "../Internal.res.mjs";
6
+ import * as BlockStore from "./BlockStore.res.mjs";
7
+ import * as Performance from "../bindings/Performance.res.mjs";
8
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
9
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
10
+ import * as Stdlib_Nullable from "@rescript/runtime/lib/es6/Stdlib_Nullable.js";
11
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
12
+
13
+ let installed = {
14
+ contents: undefined
15
+ };
16
+
17
+ function install(fetchCalls, rpcUrls) {
18
+ installed.contents = {
19
+ fetchCalls: fetchCalls,
20
+ rpcUrls: rpcUrls
21
+ };
22
+ }
23
+
24
+ function callRankOf(registration) {
25
+ return Internal.callRankOfEventName(registration.eventConfig.name);
26
+ }
27
+
28
+ function selectorOf(registration) {
29
+ let match = Internal.callRankOfEventName(registration.eventConfig.name);
30
+ if (match === 1) {
31
+ return "0x" + registration.eventConfig.name.slice(13, 21).toLowerCase();
32
+ } else {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ function wrap(source, addressStore, ecosystem, installed) {
38
+ let newrecord = {...source};
39
+ newrecord.getItemsOrThrow = async (fromBlock, toBlock, addressSet, reorgableFrom, knownHeight, partitionId, selection, itemsTarget, retry, logger) => {
40
+ let callRegistrations = selection.onEventRegistrations.filter(registration => Stdlib_Option.isSome(Internal.callRankOfEventName(registration.eventConfig.name)));
41
+ if (Utils.$$Array.isEmpty(callRegistrations)) {
42
+ return await source.getItemsOrThrow(fromBlock, toBlock, addressSet, reorgableFrom, knownHeight, partitionId, selection, itemsTarget, retry, logger);
43
+ }
44
+ let logRegistrations = selection.onEventRegistrations.filter(registration => Stdlib_Option.isNone(Internal.callRankOfEventName(registration.eventConfig.name)));
45
+ let logs;
46
+ if (Utils.$$Array.isEmpty(logRegistrations) && Utils.$$Array.isEmpty(selection.onBlockRegistrations)) {
47
+ logs = undefined;
48
+ } else {
49
+ let newrecord = {...selection};
50
+ logs = await source.getItemsOrThrow(fromBlock, toBlock, addressSet, reorgableFrom, knownHeight, partitionId, (newrecord.onEventRegistrations = logRegistrations, newrecord), itemsTarget, retry, logger);
51
+ }
52
+ let rangeEnd = logs !== undefined ? logs.latestFetchedBlockNumber : (
53
+ toBlock !== undefined ? toBlock : Math.min(knownHeight, fromBlock + 1000000 | 0)
54
+ );
55
+ let clientFiltered = contractName => {
56
+ let contractNames = selection.clientFilteredContracts;
57
+ if (contractNames !== undefined) {
58
+ return contractNames.includes(contractName);
59
+ } else {
60
+ return false;
61
+ }
62
+ };
63
+ let addresses = {};
64
+ callRegistrations.forEach(registration => {
65
+ let contractName = registration.eventConfig.contractName;
66
+ if (!registration.isWildcard && Stdlib_Option.isNone(addresses[contractName])) {
67
+ addresses[contractName] = clientFiltered(contractName) ? addressStore.contractAddresses(contractName, false) : addressSet.addressesOf(contractName);
68
+ return;
69
+ }
70
+ });
71
+ let startedAt = Performance.now();
72
+ let response;
73
+ try {
74
+ response = await installed.fetchCalls({
75
+ chainId: source.chainId,
76
+ fromBlock: fromBlock,
77
+ toBlock: rangeEnd,
78
+ registrations: callRegistrations.map(registration => ({
79
+ index: registration.index,
80
+ contractName: registration.eventConfig.contractName,
81
+ eventName: registration.eventConfig.name,
82
+ selector: selectorOf(registration),
83
+ rank: Stdlib_Option.getOr(Internal.callRankOfEventName(registration.eventConfig.name), 1),
84
+ isWildcard: registration.isWildcard,
85
+ startBlock: Stdlib_Nullable.fromOption(registration.startBlock)
86
+ })),
87
+ addresses: addresses,
88
+ rpcUrls: installed.rpcUrls
89
+ });
90
+ } catch (raw_exn) {
91
+ let exn = Primitive_exceptions.internalToException(raw_exn);
92
+ throw {
93
+ RE_EXN_ID: Source.GetItemsError,
94
+ _1: {
95
+ TAG: "FailedGettingItems",
96
+ exn: exn,
97
+ attemptedToBlock: rangeEnd,
98
+ retry: {
99
+ TAG: "WithBackoff",
100
+ message: `Failed reading the calls of blocks ` + fromBlock.toString() + ` to ` + rangeEnd.toString() + `. Attempt a retry.`,
101
+ backoffMillis: retry !== 0 ? 1000 * retry | 0 : 500
102
+ },
103
+ requestStats: []
104
+ },
105
+ Error: new Error()
106
+ };
107
+ }
108
+ let callSeconds = Performance.secondsSince(startedAt);
109
+ let registrationByIndex = {};
110
+ callRegistrations.forEach(registration => {
111
+ registrationByIndex[registration.index.toString()] = registration;
112
+ });
113
+ let latest = response.latestFetchedBlockNumber;
114
+ let callItems = Stdlib_Array.filterMap(response.items, callItem => {
115
+ let registration = registrationByIndex[callItem.registrationIndex.toString()];
116
+ let contractName = registration.eventConfig.contractName;
117
+ let ownsCall = true;
118
+ if (!registration.isWildcard) {
119
+ let address = callItem.payload.srcAddress;
120
+ ownsCall = clientFiltered(contractName) ? addressStore.isIndexedAt(address, contractName, callItem.blockNumber) : addressSet.containsAt(address, contractName, callItem.blockNumber);
121
+ }
122
+ if (!(callItem.blockNumber <= latest && ownsCall)) {
123
+ return;
124
+ }
125
+ let item_1 = source.chainId;
126
+ let item_2 = callItem.blockNumber;
127
+ let item_4 = callItem.traceAddress;
128
+ let item_5 = callItem.transactionIndex;
129
+ let item_6 = callItem.payload;
130
+ let item = {
131
+ kind: 0,
132
+ onEventRegistration: registration,
133
+ chainId: item_1,
134
+ blockNumber: item_2,
135
+ logIndex: 0,
136
+ orderPath: item_4,
137
+ transactionIndex: item_5,
138
+ payload: item_6
139
+ };
140
+ Internal.markItemCall(item, Stdlib_Option.getOr(Internal.callRankOfEventName(registration.eventConfig.name), 1));
141
+ return item;
142
+ });
143
+ let callBlocks = BlockStore.fromJs(response.blocks, ecosystem);
144
+ let callRequestStat = {
145
+ method: "getCalls",
146
+ seconds: callSeconds
147
+ };
148
+ if (logs !== undefined) {
149
+ logs.blockStore.appendPage(callBlocks);
150
+ return {
151
+ knownHeight: logs.knownHeight,
152
+ parsedQueueItems: logs.parsedQueueItems.filter(item => item.blockNumber <= latest).concat(callItems),
153
+ transactionStore: logs.transactionStore,
154
+ blockStore: logs.blockStore,
155
+ latestFetchedBlockNumber: Math.min(logs.latestFetchedBlockNumber, latest),
156
+ stats: logs.stats,
157
+ requestStats: logs.requestStats.concat([callRequestStat])
158
+ };
159
+ } else {
160
+ return {
161
+ knownHeight: Stdlib_Nullable.getOr(response.knownHeight, knownHeight),
162
+ parsedQueueItems: callItems,
163
+ transactionStore: undefined,
164
+ blockStore: callBlocks,
165
+ latestFetchedBlockNumber: latest,
166
+ stats: {
167
+ "total time elapsed (s)": callSeconds
168
+ },
169
+ requestStats: [callRequestStat]
170
+ };
171
+ }
172
+ };
173
+ return newrecord;
174
+ }
175
+
176
+ function wrapSources(sources, onEventRegistrations, addressStore, ecosystem) {
177
+ let installed$1 = installed.contents;
178
+ if (installed$1 !== undefined && onEventRegistrations.some(registration => Stdlib_Option.isSome(Internal.callRankOfEventName(registration.eventConfig.name)))) {
179
+ return sources.map(source => wrap(source, addressStore, ecosystem, installed$1));
180
+ } else {
181
+ return sources;
182
+ }
183
+ }
184
+
185
+ let openEndedSpan = 1000000;
186
+
187
+ export {
188
+ installed,
189
+ install,
190
+ openEndedSpan,
191
+ callRankOf,
192
+ selectorOf,
193
+ wrap,
194
+ wrapSources,
195
+ }
196
+ /* Utils Not a pure module */
@@ -10,6 +10,7 @@ let make = (
10
10
  ~blockStore: BlockStore.t,
11
11
  ~transactionStore: TransactionStore.t,
12
12
  ~logger: Logger.t,
13
+ ~maxAddressesPerRequest: int,
13
14
  ): array<Source.t> => {
14
15
  let chainId = chainConfig.id
15
16
  switch chainConfig.sourceConfig {
@@ -39,6 +40,7 @@ let make = (
39
40
  ~blockStore,
40
41
  ~transactionStore,
41
42
  ~logger,
43
+ ~maxAddressesPerRequest,
42
44
  )
43
45
  | Config.FuelSourceConfig({hypersync}) => [
44
46
  FuelHyperSyncSource.make({
@@ -7,7 +7,7 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
7
7
  import * as SvmHyperSyncSource from "./SvmHyperSyncSource.res.mjs";
8
8
  import * as FuelHyperSyncSource from "./FuelHyperSyncSource.res.mjs";
9
9
 
10
- function make(chainConfig, onEventRegistrations, onBlockRegistrationsOpt, addressStore, lowercaseAddresses, blockStore, transactionStore, logger) {
10
+ function make(chainConfig, onEventRegistrations, onBlockRegistrationsOpt, addressStore, lowercaseAddresses, blockStore, transactionStore, logger, maxAddressesPerRequest) {
11
11
  let onBlockRegistrations = onBlockRegistrationsOpt !== undefined ? onBlockRegistrationsOpt : [];
12
12
  let chainId = chainConfig.id;
13
13
  let sources = chainConfig.sourceConfig;
@@ -25,7 +25,7 @@ function make(chainConfig, onEventRegistrations, onBlockRegistrationsOpt, addres
25
25
  headers: headers
26
26
  };
27
27
  });
28
- return EvmChain.makeSources(chainId, onEventRegistrations, onBlockRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses, addressStore, blockStore, transactionStore, logger);
28
+ return EvmChain.makeSources(chainId, onEventRegistrations, onBlockRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses, addressStore, blockStore, transactionStore, logger, maxAddressesPerRequest);
29
29
  case "FuelSourceConfig" :
30
30
  return [FuelHyperSyncSource.make({
31
31
  chainId: chainId,
@@ -50,6 +50,7 @@ let makeSources = (
50
50
  ~blockStore,
51
51
  ~transactionStore,
52
52
  ~logger,
53
+ ~maxAddressesPerRequest,
53
54
  ) => {
54
55
  let sources = switch hyperSync {
55
56
  | Some(endpointUrl) => [
@@ -84,9 +85,17 @@ let makeSources = (
84
85
  transactionStore,
85
86
  ?ws,
86
87
  ?headers,
88
+ maxAddressesPerRequest,
89
+ logger,
87
90
  })
88
91
  let _ = sources->Array.push(source)
89
92
  })
90
93
 
91
- sources
94
+ sources->CallSource.wrapSources(
95
+ ~onEventRegistrations=onEventRegistrations->(
96
+ Utils.magic: array<Internal.evmOnEventRegistration> => array<Internal.onEventRegistration>
97
+ ),
98
+ ~addressStore,
99
+ ~ecosystem=Evm,
100
+ )
92
101
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as Env from "../Env.res.mjs";
4
4
  import * as RpcSource from "./RpcSource.res.mjs";
5
+ import * as CallSource from "./CallSource.res.mjs";
5
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
7
  import * as EvmHyperSyncSource from "./EvmHyperSyncSource.res.mjs";
7
8
 
@@ -19,7 +20,7 @@ function getSyncConfig(param) {
19
20
  };
20
21
  }
21
22
 
22
- function makeSources(chainId, onEventRegistrations, onBlockRegistrations, hyperSync, rpcs, lowercaseAddresses, addressStore, blockStore, transactionStore, logger) {
23
+ function makeSources(chainId, onEventRegistrations, onBlockRegistrations, hyperSync, rpcs, lowercaseAddresses, addressStore, blockStore, transactionStore, logger, maxAddressesPerRequest) {
23
24
  let sources = hyperSync !== undefined ? [EvmHyperSyncSource.make({
24
25
  chainId: chainId,
25
26
  endpointUrl: hyperSync,
@@ -47,11 +48,13 @@ function makeSources(chainId, onEventRegistrations, onBlockRegistrations, hyperS
47
48
  blockStore: blockStore,
48
49
  transactionStore: transactionStore,
49
50
  ws: param.ws,
50
- headers: param.headers
51
+ headers: param.headers,
52
+ maxAddressesPerRequest: maxAddressesPerRequest,
53
+ logger: logger
51
54
  });
52
55
  sources.push(source);
53
56
  });
54
- return sources;
57
+ return CallSource.wrapSources(sources, onEventRegistrations, addressStore, "evm");
55
58
  }
56
59
 
57
60
  export {
@@ -202,7 +202,7 @@ let make = (
202
202
  {height, requestStats: [{method: "getHeight", seconds}]}
203
203
  },
204
204
  getItemsOrThrow,
205
- createHeightSubscription: (~onHeight, ~onStatus) =>
206
- HyperSyncSSE.subscribe(~hyperSyncUrl=endpointUrl, ~apiToken, ~onHeight, ~onStatus),
205
+ createHeightSubscription: (~clock, ~onHeight, ~onStatus) =>
206
+ HyperSyncSSE.subscribe(~clock, ~hyperSyncUrl=endpointUrl, ~apiToken, ~onHeight, ~onStatus),
207
207
  }
208
208
  }
@@ -149,7 +149,7 @@ function make(param) {
149
149
  };
150
150
  },
151
151
  getItemsOrThrow: getItemsOrThrow,
152
- createHeightSubscription: (onHeight, onStatus) => HyperSyncSSE.subscribe(endpointUrl, apiToken, onHeight, onStatus)
152
+ createHeightSubscription: (clock, onHeight, onStatus) => HyperSyncSSE.subscribe(clock, endpointUrl, apiToken, onHeight, onStatus)
153
153
  };
154
154
  }
155
155
 
@@ -8,6 +8,7 @@ type cfg = {
8
8
  intervalCeiling: int,
9
9
  backoffMillis: int,
10
10
  queryTimeoutMillis: int,
11
+ maxAddressesPerRequest: int,
11
12
  }
12
13
 
13
14
  type nextPageParams = {
@@ -18,10 +19,12 @@ type nextPageParams = {
18
19
  onBlockRegistrationIndexes: array<int>,
19
20
  clientFilteredContracts: option<array<string>>,
20
21
  retry: int,
21
- // Blocks at or above this one can still be reorged, so a blocks-only page
22
- // reaching them is read for the hashes of its boundary blocks even with no
23
- // handler block in range. None when the range is final.
22
+ // Blocks at or above this one can still be reorged, so each of them in the
23
+ // page has its header read and its logs checked against it, even a
24
+ // blocks-only page with no handler block in range. None when the range is
25
+ // final.
24
26
  reorgableFrom?: int,
27
+ knownHeight: int,
25
28
  }
26
29
 
27
30
  // Rust reports what to do about a page it could not read rather than throwing
@@ -77,6 +80,8 @@ external classNew: (
77
80
  array<BlockItem.registrationInput>,
78
81
  ~checksumAddresses: bool,
79
82
  ~addressStore: AddressStore.t,
83
+ Logger.native,
84
+ array<string>,
80
85
  ) => t = "new"
81
86
 
82
87
  let make = (
@@ -88,6 +93,8 @@ let make = (
88
93
  ~eventRegistrations=[],
89
94
  ~onBlockRegistrations=[],
90
95
  ~addressStore,
96
+ ~maxAddressesPerRequest,
97
+ ~logger: Logger.t,
91
98
  ) =>
92
99
  Core.getAddon().evmRpcClient->classNew(
93
100
  {
@@ -100,9 +107,12 @@ let make = (
100
107
  intervalCeiling: syncConfig.intervalCeiling,
101
108
  backoffMillis: syncConfig.backoffMillis,
102
109
  queryTimeoutMillis: syncConfig.queryTimeoutMillis,
110
+ maxAddressesPerRequest,
103
111
  },
104
112
  eventRegistrations,
105
113
  onBlockRegistrations->BlockItem.toRegistrationInputs,
106
114
  ~checksumAddresses,
107
115
  ~addressStore,
116
+ logger.output.native,
117
+ logger.boundFieldsJson,
108
118
  )
@@ -3,7 +3,7 @@
3
3
  import * as Core from "../Core.res.mjs";
4
4
  import * as BlockItem from "./BlockItem.res.mjs";
5
5
 
6
- function make(url, checksumAddresses, syncConfig, maxConcurrentRequests, headers, eventRegistrationsOpt, onBlockRegistrationsOpt, addressStore) {
6
+ function make(url, checksumAddresses, syncConfig, maxConcurrentRequests, headers, eventRegistrationsOpt, onBlockRegistrationsOpt, addressStore, maxAddressesPerRequest, logger) {
7
7
  let eventRegistrations = eventRegistrationsOpt !== undefined ? eventRegistrationsOpt : [];
8
8
  let onBlockRegistrations = onBlockRegistrationsOpt !== undefined ? onBlockRegistrationsOpt : [];
9
9
  return Core.getAddon().EvmRpcClient.new({
@@ -15,8 +15,9 @@ function make(url, checksumAddresses, syncConfig, maxConcurrentRequests, headers
15
15
  accelerationAdditive: syncConfig.accelerationAdditive,
16
16
  intervalCeiling: syncConfig.intervalCeiling,
17
17
  backoffMillis: syncConfig.backoffMillis,
18
- queryTimeoutMillis: syncConfig.queryTimeoutMillis
19
- }, eventRegistrations, BlockItem.toRegistrationInputs(onBlockRegistrations), checksumAddresses, addressStore);
18
+ queryTimeoutMillis: syncConfig.queryTimeoutMillis,
19
+ maxAddressesPerRequest: maxAddressesPerRequest
20
+ }, eventRegistrations, BlockItem.toRegistrationInputs(onBlockRegistrations), checksumAddresses, addressStore, logger.output.native, logger.boundFieldsJson);
20
21
  }
21
22
 
22
23
  export {
@@ -81,8 +81,8 @@ let wsMessageSchema = S.union([
81
81
  }),
82
82
  ])
83
83
 
84
- let subscribe = (~wsUrl, ~onHeight, ~onStatus) =>
85
- HeightStream.subscribe(~staleTimeout, ~onHeight, ~onStatus, ~connect=driver => {
84
+ let subscribe = (~clock, ~wsUrl, ~onHeight, ~onStatus) =>
85
+ HeightStream.subscribe(~clock, ~staleTimeout, ~onHeight, ~onStatus, ~connect=driver => {
86
86
  let ws = WebSocket.create(wsUrl)
87
87
  let subscribed = ref(false)
88
88
 
@@ -103,7 +103,8 @@ let subscribe = (~wsUrl, ~onHeight, ~onStatus) =>
103
103
  | Some(Response({id: Some(id), isError: false})) if id === subscribeRequestIdText =>
104
104
  subscribed := true
105
105
  driver.onConnected()
106
- | Some(Response({id, isError: true})) if id->refusesSubscribe(~subscribed=subscribed.contents) =>
106
+ | Some(Response({id, isError: true}))
107
+ if id->refusesSubscribe(~subscribed=subscribed.contents) =>
107
108
  driver.onFailure(~reason=SubscribeRejected, ~detail=text)
108
109
  // A provider talking about something other than the subscription this
109
110
  // socket asked for — a rate limit, a request nobody here made. Read