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,98 @@
1
+ // A cached effect's stored outputs, read straight from storage. For the
2
+ // subgraph register pass: it runs at fetch time, outside any handler context,
3
+ // so its contract calls can't go through the effect machinery, and after
4
+ // `envio start -r` (which keeps the subgraph call caches) it would otherwise ask
5
+ // the RPC again for every call it makes.
6
+ //
7
+ // Only a chain-scoped effect's table that held rows when the run started is
8
+ // read: rows this run writes are already in the register pass's own cache.
9
+ // The calls of one turn share one storage query.
10
+
11
+ type batch = {
12
+ effect: Internal.effect,
13
+ table: Table.table,
14
+ keys: array<string>,
15
+ resolvers: array<option<Internal.effectOutput> => unit>,
16
+ }
17
+
18
+ let startupTables: ref<option<Utils.Set.t<string>>> = ref(None)
19
+
20
+ // Reset between test indexers, which each bring their own storage.
21
+ let resetStartupTables = () => startupTables := None
22
+
23
+ let tablesWithRowsAtStart = (cache: dict<Persistence.effectCacheRecord>) =>
24
+ switch startupTables.contents {
25
+ | Some(tables) => tables
26
+ | None =>
27
+ let tables = Utils.Set.make()
28
+ cache
29
+ ->Dict.valuesToArray
30
+ ->Array.forEach(record =>
31
+ if record.count > 0 {
32
+ tables->Utils.Set.add(record.tableName)->ignore
33
+ }
34
+ )
35
+ startupTables := Some(tables)
36
+ tables
37
+ }
38
+
39
+ let pending: dict<batch> = Dict.make()
40
+
41
+ let load = async (storage: Persistence.storage, batch: batch) => {
42
+ let rows =
43
+ (await storage.loadOrThrow(~table=batch.table, ~filter=EntityFilter.byIds(batch.keys)))->(
44
+ Utils.magic: array<unknown> => array<Internal.effectCacheItem>
45
+ )
46
+ let byId = Dict.make()
47
+ rows->Array.forEach(row =>
48
+ switch row.output->S.parseOrThrow(batch.effect.storageMeta.outputSchema) {
49
+ | output => byId->Dict.set(row.id, output)
50
+ | exception _ => ()
51
+ }
52
+ )
53
+ batch.keys->Array.map(key => byId->Utils.Dict.dangerouslyGetNonOption(key))
54
+ }
55
+
56
+ let flush = async (storage: Persistence.storage, tableName) => {
57
+ let batch = pending->Dict.getUnsafe(tableName)
58
+ pending->Utils.Dict.deleteInPlace(tableName)
59
+ let outputs = switch await load(storage, batch) {
60
+ | outputs => outputs
61
+ | exception _ => batch.keys->Array.map(_ => None)
62
+ }
63
+ batch.resolvers->Array.forEachWithIndex((resolve, idx) => resolve(outputs->Array.getUnsafe(idx)))
64
+ }
65
+
66
+ let cached = (effect: Internal.effect, chainId: int, input: Internal.effectInput): promise<
67
+ option<Internal.effectOutput>,
68
+ > =>
69
+ switch (
70
+ effect.crossChain,
71
+ EnvioGlobal.value.persistence->(Utils.magic: option<unknown> => option<Persistence.t>),
72
+ ) {
73
+ | (Some(false), Some({storageStatus: Ready({cache}), storage})) =>
74
+ let table = Internal.makeCacheTable(
75
+ ~effectName=effect.name,
76
+ ~scope=Chain(chainId->ChainId.fromInt),
77
+ )
78
+ if cache->tablesWithRowsAtStart->Utils.Set.has(table.tableName) {
79
+ let key =
80
+ input
81
+ ->S.reverseConvertOrThrow(effect.input)
82
+ ->Utils.Hash.makeOrThrow
83
+ ->Utils.Hash.boundCacheKey
84
+ Promise.make((resolve, _) => {
85
+ switch pending->Utils.Dict.dangerouslyGetNonOption(table.tableName) {
86
+ | Some(batch) =>
87
+ batch.keys->Array.push(key)
88
+ batch.resolvers->Array.push(resolve)
89
+ | None =>
90
+ pending->Dict.set(table.tableName, {effect, table, keys: [key], resolvers: [resolve]})
91
+ let _ = setTimeout(() => storage->flush(table.tableName)->ignore, 0)
92
+ }
93
+ })
94
+ } else {
95
+ Promise.resolve(None)
96
+ }
97
+ | _ => Promise.resolve(None)
98
+ }
@@ -0,0 +1,116 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "./Utils.res.mjs";
4
+ import * as Internal from "./Internal.res.mjs";
5
+ import * as EnvioGlobal from "./EnvioGlobal.res.mjs";
6
+ import * as EntityFilter from "./db/EntityFilter.res.mjs";
7
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8
+ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
9
+
10
+ let startupTables = {
11
+ contents: undefined
12
+ };
13
+
14
+ function resetStartupTables() {
15
+ startupTables.contents = undefined;
16
+ }
17
+
18
+ function tablesWithRowsAtStart(cache) {
19
+ let tables = startupTables.contents;
20
+ if (tables !== undefined) {
21
+ return Primitive_option.valFromOption(tables);
22
+ }
23
+ let tables$1 = new Set();
24
+ Object.values(cache).forEach(record => {
25
+ if (record.count > 0) {
26
+ tables$1.add(record.tableName);
27
+ return;
28
+ }
29
+ });
30
+ startupTables.contents = Primitive_option.some(tables$1);
31
+ return tables$1;
32
+ }
33
+
34
+ let pending = {};
35
+
36
+ async function load(storage, batch) {
37
+ let rows = await storage.loadOrThrow(EntityFilter.byIds(batch.keys), batch.table);
38
+ let byId = {};
39
+ rows.forEach(row => {
40
+ let output;
41
+ try {
42
+ output = S$RescriptSchema.parseOrThrow(row.output, batch.effect.storageMeta.outputSchema);
43
+ } catch (exn) {
44
+ return;
45
+ }
46
+ byId[row.id] = output;
47
+ });
48
+ return batch.keys.map(key => byId[key]);
49
+ }
50
+
51
+ async function flush(storage, tableName) {
52
+ let batch = pending[tableName];
53
+ Utils.Dict.deleteInPlace(pending, tableName);
54
+ let outputs;
55
+ try {
56
+ outputs = await load(storage, batch);
57
+ } catch (exn) {
58
+ outputs = batch.keys.map(param => {});
59
+ }
60
+ batch.resolvers.forEach((resolve, idx) => resolve(outputs[idx]));
61
+ }
62
+
63
+ function cached(effect, chainId, input) {
64
+ let match = effect.crossChain;
65
+ let match$1 = EnvioGlobal.value.persistence;
66
+ if (match === undefined) {
67
+ return Promise.resolve(undefined);
68
+ }
69
+ if (match) {
70
+ return Promise.resolve(undefined);
71
+ }
72
+ if (match$1 === undefined) {
73
+ return Promise.resolve(undefined);
74
+ }
75
+ let match$2 = match$1.storageStatus;
76
+ if (typeof match$2 !== "object") {
77
+ return Promise.resolve(undefined);
78
+ }
79
+ if (match$2.TAG === "Initializing") {
80
+ return Promise.resolve(undefined);
81
+ }
82
+ let storage = match$1.storage;
83
+ let table = Internal.makeCacheTable(effect.name, chainId);
84
+ if (!tablesWithRowsAtStart(match$2._0.cache).has(table.tableName)) {
85
+ return Promise.resolve(undefined);
86
+ }
87
+ let key = Utils.Hash.boundCacheKey(Utils.Hash.makeOrThrow(S$RescriptSchema.reverseConvertOrThrow(input, effect.input)));
88
+ return new Promise((resolve, param) => {
89
+ let batch = pending[table.tableName];
90
+ if (batch !== undefined) {
91
+ batch.keys.push(key);
92
+ batch.resolvers.push(resolve);
93
+ } else {
94
+ pending[table.tableName] = {
95
+ effect: effect,
96
+ table: table,
97
+ keys: [key],
98
+ resolvers: [resolve]
99
+ };
100
+ setTimeout(() => {
101
+ flush(storage, table.tableName);
102
+ }, 0);
103
+ }
104
+ });
105
+ }
106
+
107
+ export {
108
+ startupTables,
109
+ resetStartupTables,
110
+ tablesWithRowsAtStart,
111
+ pending,
112
+ load,
113
+ flush,
114
+ cached,
115
+ }
116
+ /* Utils Not a pure module */
@@ -11,6 +11,8 @@ type effectRateLimitState = {
11
11
  mutable availableCalls: int,
12
12
  mutable windowStartTime: float,
13
13
  mutable nextWindowPromise: option<promise<unit>>,
14
+ // The run's clock: a test on virtual time opens the next window by advancing.
15
+ clock: Clock.t,
14
16
  }
15
17
 
16
18
  // Per-(effect, scope) counters rendered into the envio_effect_* metrics. Live
@@ -80,9 +82,14 @@ type t = {
80
82
  // rollback; stats and the rate-limit window survive because the table does.
81
83
  tables: dict<effectCacheInMemTable>,
82
84
  unregisteredCacheCounts: dict<unregisteredCacheCount>,
85
+ clock: Clock.t,
83
86
  }
84
87
 
85
- let make = (): t => {tables: Dict.make(), unregisteredCacheCounts: Dict.make()}
88
+ let make = (~clock=Clock.real, ()): t => {
89
+ tables: Dict.make(),
90
+ unregisteredCacheCounts: Dict.make(),
91
+ clock,
92
+ }
86
93
 
87
94
  let setUnregisteredCacheCount = (self: t, ~effectName, ~scope, ~count) => {
88
95
  let tableName = Internal.EffectCache.toTableName(~effectName, ~scope)
@@ -214,8 +221,9 @@ let getTable = (self: t, ~effect: Internal.effect, ~scope: Internal.chainScope)
214
221
  callsPerDuration,
215
222
  durationMs,
216
223
  availableCalls: callsPerDuration,
217
- windowStartTime: Date.now(),
224
+ windowStartTime: self.clock.now(),
218
225
  nextWindowPromise: None,
226
+ clock: self.clock,
219
227
  })
220
228
  }
221
229
  let inMemTable: effectCacheInMemTable = {
@@ -1,13 +1,16 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Clock from "./Clock.res.mjs";
3
4
  import * as Utils from "./Utils.res.mjs";
4
5
  import * as Internal from "./Internal.res.mjs";
5
6
  import * as Performance from "./bindings/Performance.res.mjs";
6
7
 
7
- function make() {
8
+ function make(clockOpt, param) {
9
+ let clock = clockOpt !== undefined ? clockOpt : Clock.real;
8
10
  return {
9
11
  tables: {},
10
- unregisteredCacheCounts: {}
12
+ unregisteredCacheCounts: {},
13
+ clock: clock
11
14
  };
12
15
  }
13
16
 
@@ -130,8 +133,9 @@ function getTable(self, effect, scope) {
130
133
  callsPerDuration: callsPerDuration,
131
134
  durationMs: match$1.durationMs,
132
135
  availableCalls: callsPerDuration,
133
- windowStartTime: Date.now(),
134
- nextWindowPromise: undefined
136
+ windowStartTime: self.clock.now(),
137
+ nextWindowPromise: undefined,
138
+ clock: self.clock
135
139
  };
136
140
  } else {
137
141
  rateLimitState = undefined;
@@ -4,6 +4,8 @@ type effectRateLimitState = {
4
4
  mutable availableCalls: int,
5
5
  mutable windowStartTime: float,
6
6
  mutable nextWindowPromise: option<promise<unit>>,
7
+ // The run's clock: a test on virtual time opens the next window by advancing.
8
+ clock: Clock.t,
7
9
  }
8
10
 
9
11
  // Per-(effect, scope) metric counters. Survive rollback so they stay monotonic.
@@ -32,7 +34,7 @@ type effectCacheInMemTable = {
32
34
  // Opaque store of all per-(effect, scope) runtime state.
33
35
  type t
34
36
 
35
- let make: unit => t
37
+ let make: (~clock: Clock.t=?, unit) => t
36
38
  // Get, or lazily create, the in-mem table for an (effect, scope). Reuses the
37
39
  // surviving rate-limit window when the table is recreated after a rollback.
38
40
  let getTable: (t, ~effect: Internal.effect, ~scope: Internal.chainScope) => effectCacheInMemTable
package/src/EntityId.res CHANGED
@@ -1,15 +1,10 @@
1
1
  // Opaque representation of an entity id. The generated per-entity types expose
2
- // the real scalar (string / int / bigint); the generic storage and in-memory
2
+ // the real scalar (string / int / bigint / Uint8Array); the generic storage and in-memory
3
3
  // layers work with any entity's id through this type without knowing which
4
4
  // scalar backs it. The runtime value is always the real id, never a stringified
5
- // form — `toKey` derives the string only where a JS object/dict key is needed.
5
+ // form — a table's `entityIdToKey` derives the string only where a dict or Set key is needed.
6
6
  type t
7
7
 
8
8
  external unsafeOfAny: 'a => t = "%identity"
9
9
  external unsafeToAny: t => 'a = "%identity"
10
10
  external unsafeOfString: string => t = "%identity"
11
-
12
- // Stringified id used as a JS object/dict key. `String` matches how JS coerces
13
- // a value used as an object key, so an id indexes the same whether the raw
14
- // value or its key form is used for lookup, across string/int/bigint.
15
- let toKey: t => string = %raw(`String`)
@@ -1,9 +1,2 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
-
4
- let toKey = String;
5
-
6
- export {
7
- toKey,
8
- }
9
- /* toKey Not a pure module */
2
+ /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
@@ -6,7 +6,10 @@ type t = dict<InMemoryTable.Entity.t>
6
6
  let make = (entities: array<Internal.entityConfig>): t => {
7
7
  let init = Dict.make()
8
8
  entities->Array.forEach(entityConfig => {
9
- init->Dict.set((entityConfig.name :> string), InMemoryTable.Entity.make())
9
+ init->Dict.set(
10
+ (entityConfig.name :> string),
11
+ InMemoryTable.Entity.make(~entityIdToKey=entityConfig.table.entityIdToKey),
12
+ )
10
13
  })
11
14
  init
12
15
  }
@@ -6,7 +6,7 @@ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
6
6
  function make(entities) {
7
7
  let init = {};
8
8
  entities.forEach(entityConfig => {
9
- init[entityConfig.name] = InMemoryTable.Entity.make();
9
+ init[entityConfig.name] = InMemoryTable.Entity.make(entityConfig.table.entityIdToKey);
10
10
  });
11
11
  return init;
12
12
  }
package/src/Env.res CHANGED
@@ -4,6 +4,26 @@
4
4
  %%private(let envSafe = EnvSafe.make())
5
5
 
6
6
  let targetBufferSize = envSafe->EnvSafe.get("ENVIO_INDEXING_MAX_BUFFER_SIZE", S.option(S.int))
7
+
8
+ // Set once a subgraph-mode config is loaded. A subgraph's mappings run per
9
+ // event, and every fetched event that can create a data source also holds a
10
+ // live register pass and its contract calls until the response is merged, so
11
+ // the pool of events ready to process is sized for that (CrossChainState).
12
+ let subgraphMode = ref(false)
13
+
14
+ // Set with subgraphMode when the manifest declares templates: without one no
15
+ // event can create a data source, so none holds a register pass.
16
+ let subgraphHasTemplates = ref(false)
17
+
18
+ // Most events with a register pass one subgraph response may hold before it is
19
+ // cut after a block and the rest fetched again. 0 turns the cut off; unset, it
20
+ // follows what the register passes cost (ChainFetching).
21
+ let subgraphRegisterChunk = envSafe->EnvSafe.get("ENVIO_SUBGRAPH_REGISTER_CHUNK", S.option(S.int))
22
+
23
+ // How many items ahead of the one executing a subgraph handler is preloaded
24
+ // again once an entity it read as absent is created (PreloadLookahead). 0 = off.
25
+ let subgraphPreloadLookahead =
26
+ envSafe->EnvSafe.get("ENVIO_SUBGRAPH_PRELOAD_LOOKAHEAD", S.int, ~fallback=256)
7
27
  let maxAddrInPartition = envSafe->EnvSafe.get("MAX_PARTITION_SIZE", S.int, ~fallback=5_000)
8
28
 
9
29
  // Most parallel in-flight queries a single chain may have at once, across all
package/src/Env.res.mjs CHANGED
@@ -13,6 +13,18 @@ let envSafe = EnvSafe.make(undefined);
13
13
 
14
14
  let targetBufferSize = EnvSafe.get(envSafe, "ENVIO_INDEXING_MAX_BUFFER_SIZE", S$RescriptSchema.option(S$RescriptSchema.int), undefined, undefined, undefined, undefined);
15
15
 
16
+ let subgraphMode = {
17
+ contents: false
18
+ };
19
+
20
+ let subgraphHasTemplates = {
21
+ contents: false
22
+ };
23
+
24
+ let subgraphRegisterChunk = EnvSafe.get(envSafe, "ENVIO_SUBGRAPH_REGISTER_CHUNK", S$RescriptSchema.option(S$RescriptSchema.int), undefined, undefined, undefined, undefined);
25
+
26
+ let subgraphPreloadLookahead = EnvSafe.get(envSafe, "ENVIO_SUBGRAPH_PRELOAD_LOOKAHEAD", S$RescriptSchema.int, undefined, 256, undefined, undefined);
27
+
16
28
  let maxAddrInPartition = EnvSafe.get(envSafe, "MAX_PARTITION_SIZE", S$RescriptSchema.int, undefined, 5000, undefined, undefined);
17
29
 
18
30
  let clientFilterAddressThreshold = EnvSafe.get(envSafe, "ENVIO_CLIENT_FILTER_ADDRESS_THRESHOLD", S$RescriptSchema.int, undefined, (maxAddrInPartition * 100 | 0) / 5 | 0, undefined, undefined);
@@ -216,6 +228,10 @@ let maxChainConcurrency = 100;
216
228
 
217
229
  export {
218
230
  targetBufferSize,
231
+ subgraphMode,
232
+ subgraphHasTemplates,
233
+ subgraphRegisterChunk,
234
+ subgraphPreloadLookahead,
219
235
  maxAddrInPartition,
220
236
  maxChainConcurrency,
221
237
  clientFilterAddressThreshold,
@@ -125,17 +125,52 @@ let preloadBatchOrThrow = async (batch: Batch.t, ~runtime) => {
125
125
 
126
126
  let runBatchHandlersOrThrow = async (batch: Batch.t, ~runtime) => {
127
127
  let itemIdx = ref(0)
128
+ let lookahead = PreloadLookahead.active.contents
129
+ // Settled before the batch ends: one finishing after a rollback would put a
130
+ // value read before it back into memory.
131
+ let lookaheadPreloads = []
132
+ // Only read by the lookahead, which preloads items out of checkpoint order.
133
+ let checkpointIdOf = switch lookahead {
134
+ | Some(_) =>
135
+ let ids = []
136
+ batch.checkpointIds->Array.forEachWithIndex((checkpointId, checkpointIdx) => {
137
+ for _ in 1 to batch.checkpointItemsCount->Array.getUnsafe(checkpointIdx) {
138
+ ids->Array.push(checkpointId)
139
+ }
140
+ })
141
+ ids
142
+ | None => []
143
+ }
128
144
 
129
145
  for checkpointIdx in 0 to batch.checkpointIds->Array.length - 1 {
130
146
  let checkpointId = batch.checkpointIds->Array.getUnsafe(checkpointIdx)
131
147
  let checkpointItemsCount = batch.checkpointItemsCount->Array.getUnsafe(checkpointIdx)
132
148
 
133
149
  for idx in 0 to checkpointItemsCount - 1 {
134
- let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
150
+ let index = itemIdx.contents + idx
151
+ let item = batch.items->Array.getUnsafe(index)
135
152
  await runHandlerOrThrow(item, ~checkpointId, ~runtime)
153
+
154
+ switch lookahead {
155
+ | Some(lookahead) =>
156
+ lookahead->PreloadLookahead.afterItem(~index, ~preload=(ahead, aheadIdx) =>
157
+ if ahead->hasHandler {
158
+ lookaheadPreloads
159
+ ->Array.push(
160
+ runtime->preload(
161
+ ~item=ahead,
162
+ ~checkpointId=checkpointIdOf->Array.getUnsafe(aheadIdx),
163
+ ),
164
+ )
165
+ ->ignore
166
+ }
167
+ )
168
+ | None => ()
169
+ }
136
170
  }
137
171
  itemIdx := itemIdx.contents + checkpointItemsCount
138
172
  }
173
+ let _ = await Promise.all(lookaheadPreloads)
139
174
  }
140
175
 
141
176
  let registerProcessEventBatchMetrics = (
@@ -219,6 +254,7 @@ let processEventBatch = async (~batch: Batch.t, ~runtime: HandlerRuntime.t) => {
219
254
  // Materialise store-backed transactions onto payloads before any handler
220
255
  // (preload or execute) reads them.
221
256
  await materializeBatchEvents(batch, ~chainStates)
257
+ PreloadLookahead.start(~items=batch.items)
222
258
  await batch->preloadBatchOrThrow(~runtime)
223
259
  }
224
260
 
@@ -227,6 +263,7 @@ let processEventBatch = async (~batch: Batch.t, ~runtime: HandlerRuntime.t) => {
227
263
  if batch.items->Utils.Array.notEmpty {
228
264
  await batch->runBatchHandlersOrThrow(~runtime)
229
265
  }
266
+ PreloadLookahead.stop()
230
267
 
231
268
  let elapsedTimeAfterProcessing = timeRef->Performance.secondsSince
232
269
 
@@ -14,6 +14,7 @@ import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
14
14
  import * as IndexerState from "./IndexerState.res.mjs";
15
15
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
16
16
  import * as HandlerRuntime from "./HandlerRuntime.res.mjs";
17
+ import * as PreloadLookahead from "./PreloadLookahead.res.mjs";
17
18
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
18
19
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
19
20
 
@@ -138,15 +139,39 @@ async function preloadBatchOrThrow(batch, runtime) {
138
139
 
139
140
  async function runBatchHandlersOrThrow(batch, runtime) {
140
141
  let itemIdx = 0;
142
+ let lookahead = PreloadLookahead.active.contents;
143
+ let lookaheadPreloads = [];
144
+ let checkpointIdOf;
145
+ if (lookahead !== undefined) {
146
+ let ids = [];
147
+ batch.checkpointIds.forEach((checkpointId, checkpointIdx) => {
148
+ for (let _for = 1, _for_finish = batch.checkpointItemsCount[checkpointIdx]; _for <= _for_finish; ++_for) {
149
+ ids.push(checkpointId);
150
+ }
151
+ });
152
+ checkpointIdOf = ids;
153
+ } else {
154
+ checkpointIdOf = [];
155
+ }
141
156
  for (let checkpointIdx = 0, checkpointIdx_finish = batch.checkpointIds.length; checkpointIdx < checkpointIdx_finish; ++checkpointIdx) {
142
157
  let checkpointId = batch.checkpointIds[checkpointIdx];
143
158
  let checkpointItemsCount = batch.checkpointItemsCount[checkpointIdx];
144
159
  for (let idx = 0; idx < checkpointItemsCount; ++idx) {
145
- let item = batch.items[itemIdx + idx | 0];
160
+ let index = itemIdx + idx | 0;
161
+ let item = batch.items[index];
146
162
  await runHandlerOrThrow(item, checkpointId, runtime);
163
+ if (lookahead !== undefined) {
164
+ PreloadLookahead.afterItem(lookahead, index, (ahead, aheadIdx) => {
165
+ if (hasHandler(ahead)) {
166
+ lookaheadPreloads.push(preload(runtime, ahead, checkpointIdOf[aheadIdx]));
167
+ return;
168
+ }
169
+ });
170
+ }
147
171
  }
148
172
  itemIdx = itemIdx + checkpointItemsCount | 0;
149
173
  }
174
+ await Promise.all(lookaheadPreloads);
150
175
  }
151
176
 
152
177
  function registerProcessEventBatchMetrics(logger, batch, indexerState, loadDuration, handlerDuration) {
@@ -195,12 +220,14 @@ async function processEventBatch(batch, runtime) {
195
220
  let timeRef = Performance.now();
196
221
  if (Utils.$$Array.notEmpty(batch.items)) {
197
222
  await materializeBatchEvents(batch, chainStates);
223
+ PreloadLookahead.start(batch.items);
198
224
  await preloadBatchOrThrow(batch, runtime);
199
225
  }
200
226
  let elapsedTimeAfterLoaders = Performance.secondsSince(timeRef);
201
227
  if (Utils.$$Array.notEmpty(batch.items)) {
202
228
  await runBatchHandlersOrThrow(batch, runtime);
203
229
  }
230
+ PreloadLookahead.stop();
204
231
  let elapsedTimeAfterProcessing = Performance.secondsSince(timeRef);
205
232
  Writing.commitBatch(indexerState, batch);
206
233
  let handlerDuration = elapsedTimeAfterProcessing - elapsedTimeAfterLoaders;