envio 3.7.0 → 3.9.0
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.
- package/README.md +2 -2
- package/index.d.ts +399 -156
- package/package.json +6 -6
- package/src/AddressRows.res +121 -0
- package/src/AddressRows.res.mjs +143 -0
- package/src/Batch.res +2 -0
- package/src/Batch.res.mjs +2 -1
- package/src/ChainState.res +82 -68
- package/src/ChainState.res.mjs +81 -65
- package/src/ChainState.resi +14 -9
- package/src/Config.res +41 -91
- package/src/Config.res.mjs +34 -68
- package/src/ContractMapping.res +66 -0
- package/src/ContractMapping.res.mjs +73 -0
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +4 -0
- package/src/Envio.res +54 -76
- package/src/EventConfigBuilder.res +157 -30
- package/src/EventConfigBuilder.res.mjs +118 -24
- package/src/FetchState.res +59 -67
- package/src/FetchState.res.mjs +34 -44
- package/src/HandlerRegister.res +20 -11
- package/src/HandlerRegister.res.mjs +22 -5
- package/src/Hasura.res +30 -22
- package/src/Hasura.res.mjs +11 -5
- package/src/InMemoryStore.res +18 -36
- package/src/InMemoryStore.res.mjs +12 -26
- package/src/IndexerState.res +21 -1
- package/src/IndexerState.res.mjs +9 -3
- package/src/IndexerState.resi +1 -0
- package/src/Internal.res +33 -13
- package/src/Internal.res.mjs +12 -16
- package/src/Main.res +27 -20
- package/src/Main.res.mjs +19 -14
- package/src/MemoryStorage.res +78 -73
- package/src/MemoryStorage.res.mjs +66 -81
- package/src/Metrics.res +15 -1
- package/src/Metrics.res.mjs +5 -1
- package/src/Persistence.res +34 -18
- package/src/Persistence.res.mjs +8 -5
- package/src/PgStorage.res +189 -66
- package/src/PgStorage.res.mjs +93 -59
- package/src/Rollback.res +14 -10
- package/src/Rollback.res.mjs +4 -2
- package/src/SimulateItems.res +254 -9
- package/src/SimulateItems.res.mjs +214 -47
- package/src/TestIndexer.res +119 -121
- package/src/TestIndexer.res.mjs +95 -100
- package/src/Utils.res +7 -0
- package/src/Utils.res.mjs +9 -2
- package/src/Writing.res +2 -0
- package/src/Writing.res.mjs +2 -1
- package/src/bindings/ClickHouse.res +39 -6
- package/src/bindings/ClickHouse.res.mjs +29 -4
- package/src/bindings/NodeJs.res +9 -0
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/bindings/Postgres.res +9 -0
- package/src/bindings/Postgres.res.mjs +3 -0
- package/src/db/EntityHistory.res +12 -18
- package/src/db/EntityHistory.res.mjs +3 -14
- package/src/db/InternalTable.res +182 -65
- package/src/db/InternalTable.res.mjs +183 -73
- package/src/db/Table.res +24 -0
- package/src/db/Table.res.mjs +20 -1
- package/src/sources/AddressSet.res +0 -22
- package/src/sources/AddressStore.res +48 -88
- package/src/sources/AddressStore.res.mjs +11 -22
- package/src/sources/EvmHyperSyncSource.res +3 -2
- package/src/sources/SimulateSource.res +8 -4
- package/src/sources/SimulateSource.res.mjs +7 -3
- package/src/sources/Svm.res +34 -7
- package/src/sources/Svm.res.mjs +32 -4
- package/src/sources/SvmHyperSyncClient.res +24 -30
- package/src/sources/SvmHyperSyncClient.res.mjs +3 -2
- package/src/sources/SvmHyperSyncSource.res +88 -36
- package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
- package/src/sources/TransactionStore.res +38 -0
- package/src/sources/TransactionStore.res.mjs +5 -0
- package/svm.schema.json +37 -82
package/src/ChainState.res.mjs
CHANGED
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Env from "./Env.res.mjs";
|
|
4
4
|
import * as Svm from "./sources/Svm.res.mjs";
|
|
5
|
+
import * as Core from "./Core.res.mjs";
|
|
5
6
|
import * as Batch from "./Batch.res.mjs";
|
|
6
7
|
import * as Utils from "./Utils.res.mjs";
|
|
7
8
|
import * as ChainId from "./ChainId.res.mjs";
|
|
8
9
|
import * as Logging from "./Logging.res.mjs";
|
|
9
|
-
import * as ChainMap from "./ChainMap.res.mjs";
|
|
10
10
|
import * as EvmChain from "./sources/EvmChain.res.mjs";
|
|
11
11
|
import * as FieldMask from "./sources/FieldMask.res.mjs";
|
|
12
12
|
import * as BlockStore from "./sources/BlockStore.res.mjs";
|
|
13
13
|
import * as FetchState from "./FetchState.res.mjs";
|
|
14
|
+
import * as AddressRows from "./AddressRows.res.mjs";
|
|
14
15
|
import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
|
|
15
16
|
import * as AddressStore from "./sources/AddressStore.res.mjs";
|
|
16
17
|
import * as EntityTables from "./EntityTables.res.mjs";
|
|
@@ -20,6 +21,7 @@ import * as SourceManager from "./sources/SourceManager.res.mjs";
|
|
|
20
21
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
21
22
|
import * as SimulateSource from "./sources/SimulateSource.res.mjs";
|
|
22
23
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
24
|
+
import * as ContractMapping from "./ContractMapping.res.mjs";
|
|
23
25
|
import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
|
|
24
26
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
25
27
|
import * as TransactionStore from "./sources/TransactionStore.res.mjs";
|
|
@@ -27,18 +29,26 @@ import * as SvmHyperSyncSource from "./sources/SvmHyperSyncSource.res.mjs";
|
|
|
27
29
|
import * as FuelHyperSyncSource from "./sources/FuelHyperSyncSource.res.mjs";
|
|
28
30
|
import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
|
|
29
31
|
|
|
30
|
-
function
|
|
32
|
+
function configStorageRows(chainConfig, ecosystem, contractMapping) {
|
|
31
33
|
let addresses = [];
|
|
34
|
+
let contractIds = [];
|
|
32
35
|
chainConfig.contracts.forEach(contract => {
|
|
36
|
+
let contractId = ContractMapping.idOfOrThrow(contractMapping, contract.name, undefined);
|
|
33
37
|
contract.addresses.forEach(address => {
|
|
34
|
-
addresses.push(
|
|
35
|
-
|
|
36
|
-
contractName: contract.name,
|
|
37
|
-
registrationBlock: -1
|
|
38
|
-
});
|
|
38
|
+
addresses.push(address);
|
|
39
|
+
contractIds.push(contractId);
|
|
39
40
|
});
|
|
40
41
|
});
|
|
41
|
-
return addresses
|
|
42
|
+
return Core.getAddon().encodeAddresses(ecosystem, addresses).map((address, idx) => ({
|
|
43
|
+
chainId: chainConfig.id,
|
|
44
|
+
address: address,
|
|
45
|
+
contractId: contractIds[idx],
|
|
46
|
+
registrationBlock: AddressRows.configRegistrationBlock
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function seedConfigAddresses(table, chainConfigs, ecosystem, contractMapping) {
|
|
51
|
+
chainConfigs.forEach(chainConfig => AddressRows.Table.insertMany(table, configStorageRows(chainConfig, ecosystem, contractMapping)));
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
function validateOnEventRegistrations(chainId, registrations) {
|
|
@@ -94,17 +104,21 @@ function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, so
|
|
|
94
104
|
};
|
|
95
105
|
}
|
|
96
106
|
|
|
97
|
-
function
|
|
98
|
-
let
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
names.add(contract.name);
|
|
102
|
-
});
|
|
107
|
+
function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, contractMapping, registrationsByChainId, reducedPollingInterval) {
|
|
108
|
+
let chainId = chainConfig.id;
|
|
109
|
+
let logger = Logging.createChild({
|
|
110
|
+
chainId: chainId
|
|
103
111
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
let progressBlockNumber = resumedChainState.progressBlockNumber >= 0 ? resumedChainState.progressBlockNumber : resumedChainState.startBlock - 1 | 0;
|
|
113
|
+
let addressRows = resumedChainState.addressRows;
|
|
114
|
+
let startBlock = resumedChainState.startBlock;
|
|
115
|
+
let endBlock = resumedChainState.endBlock;
|
|
116
|
+
let firstEventBlockOpt = Primitive_option.some(resumedChainState.firstEventBlockNumber);
|
|
117
|
+
let timestampCaughtUpToHeadOrEndblock = resumedChainState.timestampCaughtUpToHeadOrEndblock;
|
|
118
|
+
let numEventsProcessed = resumedChainState.numEventsProcessed;
|
|
119
|
+
let maxReorgDepth = resumedChainState.maxReorgDepth;
|
|
120
|
+
let knownHeightOpt = resumedChainState.sourceBlockNumber;
|
|
121
|
+
let isResumedOpt = true;
|
|
108
122
|
let firstEventBlock = firstEventBlockOpt !== undefined ? Primitive_option.valFromOption(firstEventBlockOpt) : undefined;
|
|
109
123
|
let knownHeight = knownHeightOpt !== undefined ? knownHeightOpt : 0;
|
|
110
124
|
let isResumed = isResumedOpt !== undefined ? isResumedOpt : false;
|
|
@@ -120,7 +134,7 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
120
134
|
}
|
|
121
135
|
});
|
|
122
136
|
let lowercaseAddresses = config.lowercaseAddresses;
|
|
123
|
-
let addressStore = AddressStore.make(config.ecosystem.name, !lowercaseAddresses, AddressStore.contractsOf(onEventRegistrations,
|
|
137
|
+
let addressStore = AddressStore.make(config.ecosystem.name, !lowercaseAddresses, AddressStore.contractsOf(onEventRegistrations, contractMapping));
|
|
124
138
|
let match$1 = config.ecosystem.name;
|
|
125
139
|
let tmp;
|
|
126
140
|
switch (match$1) {
|
|
@@ -132,13 +146,13 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
132
146
|
tmp = undefined;
|
|
133
147
|
break;
|
|
134
148
|
}
|
|
135
|
-
let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, addressStore,
|
|
149
|
+
let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, addressStore, addressRows, config.maxAddrInPartition, chainConfig.id, (config.batchSize << 1), knownHeight, progressBlockNumber, match.onBlockRegistrations, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock), Primitive_option.some(tmp), isResumed);
|
|
136
150
|
let chainReorgCheckpoints = Stdlib_Array.filterMap(reorgCheckpoints, reorgCheckpoint => {
|
|
137
151
|
if (reorgCheckpoint.chain_id === chainConfig.id) {
|
|
138
152
|
return reorgCheckpoint;
|
|
139
153
|
}
|
|
140
154
|
});
|
|
141
|
-
let chainId = chainConfig.id;
|
|
155
|
+
let chainId$1 = chainConfig.id;
|
|
142
156
|
let sources = chainConfig.sourceConfig;
|
|
143
157
|
let sources$1;
|
|
144
158
|
switch (sources.TAG) {
|
|
@@ -155,11 +169,11 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
155
169
|
headers: headers
|
|
156
170
|
};
|
|
157
171
|
});
|
|
158
|
-
sources$1 = EvmChain.makeSources(chainId, onEventRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses, addressStore);
|
|
172
|
+
sources$1 = EvmChain.makeSources(chainId$1, onEventRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses, addressStore);
|
|
159
173
|
break;
|
|
160
174
|
case "FuelSourceConfig" :
|
|
161
175
|
sources$1 = [FuelHyperSyncSource.make({
|
|
162
|
-
chainId: chainId,
|
|
176
|
+
chainId: chainId$1,
|
|
163
177
|
endpointUrl: sources.hypersync,
|
|
164
178
|
apiToken: Env.envioApiToken,
|
|
165
179
|
onEventRegistrations: onEventRegistrations,
|
|
@@ -170,18 +184,18 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
170
184
|
let rpc = sources.rpc;
|
|
171
185
|
let hypersync = sources.hypersync;
|
|
172
186
|
sources$1 = hypersync !== undefined ? [SvmHyperSyncSource.make({
|
|
173
|
-
chainId: chainId,
|
|
187
|
+
chainId: chainId$1,
|
|
174
188
|
endpointUrl: hypersync,
|
|
175
189
|
apiToken: Env.envioApiToken,
|
|
176
190
|
onEventRegistrations: onEventRegistrations,
|
|
177
191
|
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
|
|
178
192
|
addressStore: addressStore
|
|
179
193
|
})] : (
|
|
180
|
-
rpc !== undefined ? [Svm.makeRPCSource(chainId, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + ChainId.toString(chainId) + ` has no SVM data source`)
|
|
194
|
+
rpc !== undefined ? [Svm.makeRPCSource(chainId$1, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + ChainId.toString(chainId$1) + ` has no SVM data source`)
|
|
181
195
|
);
|
|
182
196
|
break;
|
|
183
197
|
case "SimulateSourceConfig" :
|
|
184
|
-
sources$1 = [SimulateSource.make(sources.items, sources.endBlock, chainId, addressStore, config.ecosystem.name)];
|
|
198
|
+
sources$1 = [SimulateSource.make(sources.items, sources.endBlock, chainId$1, addressStore, config.ecosystem.name, Primitive_option.some(sources.transactionStore), Primitive_option.some(sources.blockStore))];
|
|
185
199
|
break;
|
|
186
200
|
case "CustomSources" :
|
|
187
201
|
sources$1 = sources._0;
|
|
@@ -197,23 +211,7 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
197
211
|
}
|
|
198
212
|
let firstEventBlock$1 = fetchState.firstEventBlock;
|
|
199
213
|
let chainDensity = firstEventBlock$1 !== undefined && progressBlockNumber > firstEventBlock$1 && numEventsProcessed > 0 ? numEventsProcessed / (progressBlockNumber - firstEventBlock$1 | 0) : undefined;
|
|
200
|
-
return make(chainConfig, fetchState, onEventRegistrations, addressStore, SourceManager.make(sources$1, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), progressBlockNumber, Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), config.shouldRollbackOnReorg, maxReorgDepth, numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, Primitive_option.some(TransactionStore.make(config.ecosystem.name, !lowercaseAddresses)), Primitive_option.some(chainDensity), Primitive_option.some(blockStore), config.reorgThresholdReadyTolerance, EntityTables.perChain(config.
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function makeFromConfig(chainConfig, config, registrationsByChainId, knownHeight) {
|
|
204
|
-
let logger = Logging.createChild({
|
|
205
|
-
chainId: chainConfig.id
|
|
206
|
-
});
|
|
207
|
-
return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrationsByChainId, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined, undefined);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval) {
|
|
211
|
-
let chainId = chainConfig.id;
|
|
212
|
-
let logger = Logging.createChild({
|
|
213
|
-
chainId: chainId
|
|
214
|
-
});
|
|
215
|
-
let progressBlockNumber = resumedChainState.progressBlockNumber >= 0 ? resumedChainState.progressBlockNumber : resumedChainState.startBlock - 1 | 0;
|
|
216
|
-
return makeInternal(chainConfig, resumedChainState.indexingAddresses, resumedChainState.startBlock, resumedChainState.endBlock, Primitive_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrationsByChainId, logger, resumedChainState.timestampCaughtUpToHeadOrEndblock, resumedChainState.numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, resumedChainState.maxReorgDepth, resumedChainState.sourceBlockNumber, true, reducedPollingInterval);
|
|
214
|
+
return make(chainConfig, fetchState, onEventRegistrations, addressStore, SourceManager.make(sources$1, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), progressBlockNumber, Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), config.shouldRollbackOnReorg, maxReorgDepth, numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, Primitive_option.some(TransactionStore.make(config.ecosystem.name, !lowercaseAddresses)), Primitive_option.some(chainDensity), Primitive_option.some(blockStore), config.reorgThresholdReadyTolerance, EntityTables.perChain(config.userEntities), logger);
|
|
217
215
|
}
|
|
218
216
|
|
|
219
217
|
function logger(cs) {
|
|
@@ -567,6 +565,11 @@ async function applyTransactionGroups(store, g) {
|
|
|
567
565
|
payloads.forEach(payload => {
|
|
568
566
|
payload.transaction = tx;
|
|
569
567
|
});
|
|
568
|
+
let match = tx["accountActivities"];
|
|
569
|
+
if (match !== undefined) {
|
|
570
|
+
payloads.forEach(payload => Svm.attachAccountActivities(payload, tx));
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
570
573
|
});
|
|
571
574
|
return;
|
|
572
575
|
}
|
|
@@ -716,6 +719,10 @@ function toMetrics(cs) {
|
|
|
716
719
|
startBlock: cs.fetchState.startBlock,
|
|
717
720
|
endBlock: cs.fetchState.endBlock,
|
|
718
721
|
numAddresses: cs.addressStore.size(),
|
|
722
|
+
addressesByContract: cs.addressStore.contractCounts().map(param => [
|
|
723
|
+
param.contractName,
|
|
724
|
+
param.count
|
|
725
|
+
]),
|
|
719
726
|
isReady: cs.timestampCaughtUpToHeadOrEndblock !== undefined,
|
|
720
727
|
sourceBlockNumber: cs.fetchState.knownHeight,
|
|
721
728
|
progressBlockNumber: cs.committedProgressBlockNumber,
|
|
@@ -851,35 +858,44 @@ function markReady(cs, readyAt) {
|
|
|
851
858
|
}
|
|
852
859
|
|
|
853
860
|
function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTargetBlockNumber, isReorgChain) {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
cs.
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
861
|
+
let rollbackTo = targetBlockNumber => {
|
|
862
|
+
let match = FetchState.rollback(cs.fetchState, cs.addressStore, targetBlockNumber);
|
|
863
|
+
cs.fetchState = match.fetchState;
|
|
864
|
+
return match.rolledBackAddresses.map(param => ({
|
|
865
|
+
chainId: cs.chainConfig.id,
|
|
866
|
+
address: param.address,
|
|
867
|
+
contractId: param.contractId
|
|
868
|
+
}));
|
|
869
|
+
};
|
|
870
|
+
if (newProgressBlockNumber !== undefined) {
|
|
871
|
+
let newTotalEventsProcessed = cs.numEventsProcessed - Stdlib_Option.getOrThrow(eventsProcessedDiff, "Missing events-processed diff for rolled-back chain");
|
|
872
|
+
let safeCheckpointTracking = cs.safeCheckpointTracking;
|
|
873
|
+
if (safeCheckpointTracking !== undefined) {
|
|
874
|
+
cs.safeCheckpointTracking = SafeCheckpointTracking.rollback(safeCheckpointTracking, newProgressBlockNumber);
|
|
864
875
|
}
|
|
876
|
+
let rolledBackAddresses = rollbackTo(newProgressBlockNumber);
|
|
877
|
+
cs.transactionStore.rollback(newProgressBlockNumber);
|
|
878
|
+
cs.blockStore.rollback(newProgressBlockNumber);
|
|
879
|
+
cs.committedProgressBlockNumber = newProgressBlockNumber;
|
|
880
|
+
cs.processingBlockNumber = newProgressBlockNumber;
|
|
881
|
+
cs.numEventsProcessed = newTotalEventsProcessed;
|
|
882
|
+
return rolledBackAddresses;
|
|
865
883
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
if (safeCheckpointTracking !== undefined) {
|
|
869
|
-
cs.safeCheckpointTracking = SafeCheckpointTracking.rollback(safeCheckpointTracking, newProgressBlockNumber);
|
|
884
|
+
if (!isReorgChain) {
|
|
885
|
+
return [];
|
|
870
886
|
}
|
|
871
|
-
|
|
872
|
-
cs.transactionStore.rollback(
|
|
873
|
-
cs.blockStore.rollback(
|
|
874
|
-
cs.committedProgressBlockNumber =
|
|
875
|
-
cs.processingBlockNumber =
|
|
876
|
-
|
|
887
|
+
let rolledBackAddresses$1 = rollbackTo(rollbackTargetBlockNumber);
|
|
888
|
+
cs.transactionStore.rollback(rollbackTargetBlockNumber);
|
|
889
|
+
cs.blockStore.rollback(rollbackTargetBlockNumber);
|
|
890
|
+
cs.committedProgressBlockNumber = Primitive_int.min(cs.committedProgressBlockNumber, rollbackTargetBlockNumber);
|
|
891
|
+
cs.processingBlockNumber = Primitive_int.min(cs.processingBlockNumber, rollbackTargetBlockNumber);
|
|
892
|
+
return rolledBackAddresses$1;
|
|
877
893
|
}
|
|
878
894
|
|
|
879
895
|
export {
|
|
880
|
-
|
|
896
|
+
configStorageRows,
|
|
897
|
+
seedConfigAddresses,
|
|
881
898
|
make,
|
|
882
|
-
makeFromConfig,
|
|
883
899
|
makeFromDbState,
|
|
884
900
|
logger,
|
|
885
901
|
blockStore,
|
package/src/ChainState.resi
CHANGED
|
@@ -3,7 +3,18 @@
|
|
|
3
3
|
|
|
4
4
|
type t
|
|
5
5
|
|
|
6
|
-
let
|
|
6
|
+
let configStorageRows: (
|
|
7
|
+
Config.chain,
|
|
8
|
+
~ecosystem: Ecosystem.name,
|
|
9
|
+
~contractMapping: ContractMapping.t,
|
|
10
|
+
) => array<AddressRows.row>
|
|
11
|
+
|
|
12
|
+
let seedConfigAddresses: (
|
|
13
|
+
AddressRows.Table.t,
|
|
14
|
+
~chainConfigs: array<Config.chain>,
|
|
15
|
+
~ecosystem: Ecosystem.name,
|
|
16
|
+
~contractMapping: ContractMapping.t,
|
|
17
|
+
) => unit
|
|
7
18
|
|
|
8
19
|
let make: (
|
|
9
20
|
~chainConfig: Config.chain,
|
|
@@ -26,13 +37,6 @@ let make: (
|
|
|
26
37
|
~logger: Pino.t,
|
|
27
38
|
) => t
|
|
28
39
|
|
|
29
|
-
let makeFromConfig: (
|
|
30
|
-
Config.chain,
|
|
31
|
-
~config: Config.t,
|
|
32
|
-
~registrationsByChainId: HandlerRegister.registrationsByChainId,
|
|
33
|
-
~knownHeight: int,
|
|
34
|
-
) => t
|
|
35
|
-
|
|
36
40
|
let makeFromDbState: (
|
|
37
41
|
Config.chain,
|
|
38
42
|
~resumedChainState: Persistence.initialChainState,
|
|
@@ -40,6 +44,7 @@ let makeFromDbState: (
|
|
|
40
44
|
~isInReorgThreshold: bool,
|
|
41
45
|
~isRealtime: bool,
|
|
42
46
|
~config: Config.t,
|
|
47
|
+
~contractMapping: ContractMapping.t,
|
|
43
48
|
~registrationsByChainId: HandlerRegister.registrationsByChainId,
|
|
44
49
|
~reducedPollingInterval: int=?,
|
|
45
50
|
) => t
|
|
@@ -158,4 +163,4 @@ let rollback: (
|
|
|
158
163
|
~eventsProcessedDiff: option<float>,
|
|
159
164
|
~rollbackTargetBlockNumber: int,
|
|
160
165
|
~isReorgChain: bool,
|
|
161
|
-
) =>
|
|
166
|
+
) => array<AddressRows.key>
|
package/src/Config.res
CHANGED
|
@@ -33,13 +33,19 @@ type sourceConfig =
|
|
|
33
33
|
// A `simulate` run: the items the test fed in, parsed against the chain's
|
|
34
34
|
// registrations. The source itself is built with the chain's address store,
|
|
35
35
|
// like every other source, so it can apply the same gates.
|
|
36
|
-
| SimulateSourceConfig({
|
|
36
|
+
| SimulateSourceConfig({
|
|
37
|
+
items: array<Internal.item>,
|
|
38
|
+
endBlock: int,
|
|
39
|
+
transactionStore?: TransactionStore.t,
|
|
40
|
+
blockStore?: BlockStore.t,
|
|
41
|
+
})
|
|
37
42
|
// For tests: pass custom sources directly
|
|
38
43
|
| CustomSources(array<Source.t>)
|
|
39
44
|
|
|
40
45
|
type chain = {
|
|
41
46
|
name: string,
|
|
42
47
|
id: ChainId.t,
|
|
48
|
+
ecosystem: Ecosystem.name,
|
|
43
49
|
startBlock: int,
|
|
44
50
|
endBlock?: int,
|
|
45
51
|
maxReorgDepth: int,
|
|
@@ -101,6 +107,9 @@ type t = {
|
|
|
101
107
|
// they can express fits an INTEGER.
|
|
102
108
|
chainIdMode: ChainId.mode,
|
|
103
109
|
chainMap: ChainMap.t<chain>,
|
|
110
|
+
// Derived from every chain's contracts, so an id means the same contract on
|
|
111
|
+
// every chain and on every restart.
|
|
112
|
+
contractMapping: ContractMapping.t,
|
|
104
113
|
defaultChain: option<chain>,
|
|
105
114
|
ecosystem: Ecosystem.t,
|
|
106
115
|
enableRawEvents: bool,
|
|
@@ -117,75 +126,9 @@ type t = {
|
|
|
117
126
|
isDev: bool,
|
|
118
127
|
userEntitiesByName: dict<Internal.entityConfig>,
|
|
119
128
|
userEntities: array<Internal.entityConfig>,
|
|
120
|
-
allEntities: array<Internal.entityConfig>,
|
|
121
129
|
allEnums: array<Table.enumConfig<Table.enum>>,
|
|
122
130
|
}
|
|
123
131
|
|
|
124
|
-
module EnvioAddresses = {
|
|
125
|
-
let name = "envio_addresses"
|
|
126
|
-
let index = -1
|
|
127
|
-
|
|
128
|
-
let makeId = (~chainId: ChainId.t, ~address) => {
|
|
129
|
-
chainId->ChainId.toString ++ "-" ++ address->Address.toString
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
type t = {
|
|
133
|
-
id: string,
|
|
134
|
-
@as("chain_id") chainId: ChainId.t,
|
|
135
|
-
@as("registration_block") registrationBlock: int,
|
|
136
|
-
// Vestigial: always written as -1 and never read back. The column stays so
|
|
137
|
-
// an existing schema doesn't need a migration.
|
|
138
|
-
@as("registration_log_index") registrationLogIndex: int,
|
|
139
|
-
@as("contract_name") contractName: string,
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Extract the raw contract address from the composite id ({chainId}-{address}).
|
|
143
|
-
// Inverse of makeId. Keep in sync with makeId above and the SUBSTRING SQL in
|
|
144
|
-
// InternalTable.Chains.makeGetInitialStateQuery.
|
|
145
|
-
let getAddress = (entity: t): Address.t => {
|
|
146
|
-
let sepIdx = entity.id->String.indexOf("-")
|
|
147
|
-
entity.id
|
|
148
|
-
->String.slice(~start=sepIdx + 1, ~end=entity.id->String.length)
|
|
149
|
-
->Address.unsafeFromString
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
let schema = S.schema(s => {
|
|
153
|
-
id: s.matches(S.string),
|
|
154
|
-
chainId: s.matches(ChainId.schema),
|
|
155
|
-
registrationBlock: s.matches(S.int),
|
|
156
|
-
registrationLogIndex: s.matches(S.int),
|
|
157
|
-
contractName: s.matches(S.string),
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
let table = Table.mkTable(
|
|
161
|
-
name,
|
|
162
|
-
~fields=[
|
|
163
|
-
Table.mkField("id", String, ~isPrimaryKey=true, ~fieldSchema=S.string),
|
|
164
|
-
Table.mkField("chain_id", ChainId, ~fieldSchema=ChainId.schema),
|
|
165
|
-
Table.mkField("registration_block", Int32, ~fieldSchema=S.int),
|
|
166
|
-
// -1 sentinel when registered from a block handler (no log index)
|
|
167
|
-
Table.mkField("registration_log_index", Int32, ~fieldSchema=S.int),
|
|
168
|
-
Table.mkField("contract_name", String, ~fieldSchema=S.string),
|
|
169
|
-
],
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
external castToInternal: t => Internal.entity = "%identity"
|
|
173
|
-
|
|
174
|
-
let entityConfig = {
|
|
175
|
-
Internal.name,
|
|
176
|
-
index,
|
|
177
|
-
schema,
|
|
178
|
-
table,
|
|
179
|
-
// Internal address tracking is Postgres-only; the global config is
|
|
180
|
-
// always required to have Postgres enabled (Storage::resolve forbids
|
|
181
|
-
// a Postgres-disabled global), so this is safe regardless of mode.
|
|
182
|
-
storage: {postgres: true, clickhouse: false},
|
|
183
|
-
// The table already keys rows by chain through the composite `id`, so the
|
|
184
|
-
// per-chain mode must not append a second chain-id column to it.
|
|
185
|
-
crossChain: true,
|
|
186
|
-
}->Internal.fromGenericEntityConfig
|
|
187
|
-
}
|
|
188
|
-
|
|
189
132
|
type rpcSourceFor = | @as("sync") Sync | @as("fallback") Fallback | @as("realtime") Realtime
|
|
190
133
|
|
|
191
134
|
let rpcSourceForSchema = S.enum([Sync, Fallback, Realtime])
|
|
@@ -235,9 +178,6 @@ let svmEventDescriptorSchema = S.schema(s =>
|
|
|
235
178
|
{
|
|
236
179
|
"discriminator": s.matches(S.option(S.string)),
|
|
237
180
|
"discriminatorByteLen": s.matches(S.int),
|
|
238
|
-
"transactionFields": s.matches(S.array(Internal.svmTransactionFieldSchema)),
|
|
239
|
-
"blockFields": s.matches(S.option(S.array(Internal.svmBlockFieldSchema))),
|
|
240
|
-
"includeLogs": s.matches(S.bool),
|
|
241
181
|
// An array of AND-groups OR-ed together: the CLI normalizes both the flat
|
|
242
182
|
// and `any_of` YAML shapes to `Vec<Vec<SvmAccountFilterJson>>`.
|
|
243
183
|
"accountFilters": s.matches(
|
|
@@ -348,10 +288,18 @@ let propertySchema = S.schema(s =>
|
|
|
348
288
|
}
|
|
349
289
|
)
|
|
350
290
|
|
|
291
|
+
let clickhouseSkippingIndexSchema: S.t<Internal.clickhouseSkippingIndex> = S.object(s => {
|
|
292
|
+
Internal.name: s.field("name", S.string),
|
|
293
|
+
expr: s.field("expr", S.string),
|
|
294
|
+
type_: s.field("type", S.string),
|
|
295
|
+
granularity: ?s.field("granularity", S.option(S.int)),
|
|
296
|
+
})
|
|
297
|
+
|
|
351
298
|
let clickhouseTableOptionsSchema: S.t<Internal.clickhouseTableOptions> = S.object(s => {
|
|
352
299
|
Internal.partitionBy: ?s.field("partitionBy", S.option(S.string)),
|
|
353
300
|
orderBy: ?s.field("orderBy", S.option(S.array(S.string))),
|
|
354
301
|
ttl: ?s.field("ttl", S.option(S.string)),
|
|
302
|
+
skippingIndexes: ?s.field("skippingIndexes", S.option(S.array(clickhouseSkippingIndexSchema))),
|
|
355
303
|
})
|
|
356
304
|
|
|
357
305
|
// The entity's `clickhouse` storage arg mirrors the @storage directive:
|
|
@@ -377,6 +325,7 @@ let entityJsonSchema = S.schema(s =>
|
|
|
377
325
|
"name": s.matches(S.string),
|
|
378
326
|
"crossChain": s.matches(S.option(S.bool)),
|
|
379
327
|
"storage": s.matches(S.option(entityStorageSchema)),
|
|
328
|
+
"internal": s.matches(S.option(S.bool)),
|
|
380
329
|
"properties": s.matches(S.array(propertySchema)),
|
|
381
330
|
"derivedFields": s.matches(S.option(S.array(derivedFieldSchema))),
|
|
382
331
|
"compositeIndices": s.matches(S.option(S.array(S.array(compositeIndexFieldSchema)))),
|
|
@@ -580,6 +529,7 @@ let parseEntitiesFromJson = (
|
|
|
580
529
|
table,
|
|
581
530
|
storage,
|
|
582
531
|
crossChain,
|
|
532
|
+
internal: entityJson["internal"]->Option.getOr(false),
|
|
583
533
|
}->Internal.fromGenericEntityConfig
|
|
584
534
|
})
|
|
585
535
|
}
|
|
@@ -616,6 +566,14 @@ let publicConfigSchema = S.schema(s =>
|
|
|
616
566
|
}
|
|
617
567
|
)
|
|
618
568
|
|
|
569
|
+
let contractMappingOf = (~chainConfigs: array<chain>): ContractMapping.t => {
|
|
570
|
+
let names = []
|
|
571
|
+
chainConfigs->Array.forEach(chain =>
|
|
572
|
+
chain.contracts->Array.forEach(contract => names->Array.push(contract.name)->ignore)
|
|
573
|
+
)
|
|
574
|
+
ContractMapping.make(~names)
|
|
575
|
+
}
|
|
576
|
+
|
|
619
577
|
let fromPublic = (publicConfigJson: JSON.t) => {
|
|
620
578
|
let maxAddrInPartition = Env.maxAddrInPartition
|
|
621
579
|
// Parse public config
|
|
@@ -796,9 +754,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
796
754
|
"svm": option<{
|
|
797
755
|
"discriminator": option<string>,
|
|
798
756
|
"discriminatorByteLen": int,
|
|
799
|
-
"transactionFields": array<Internal.svmTransactionField>,
|
|
800
|
-
"blockFields": option<array<Internal.svmBlockField>>,
|
|
801
|
-
"includeLogs": bool,
|
|
802
757
|
"accountFilters": option<
|
|
803
758
|
array<array<{"position": int, "values": array<string>}>>,
|
|
804
759
|
>,
|
|
@@ -832,9 +787,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
832
787
|
~programId,
|
|
833
788
|
~discriminator=svm["discriminator"],
|
|
834
789
|
~discriminatorByteLen=svm["discriminatorByteLen"],
|
|
835
|
-
~transactionFields=svm["transactionFields"],
|
|
836
|
-
~blockFields=?svm["blockFields"],
|
|
837
|
-
~includeLogs=svm["includeLogs"],
|
|
838
790
|
~accountFilters,
|
|
839
791
|
~isInner=svm["isInner"],
|
|
840
792
|
~accounts=svm["accounts"]->Option.getOr([]),
|
|
@@ -923,25 +875,24 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
923
875
|
}
|
|
924
876
|
})
|
|
925
877
|
|
|
926
|
-
//
|
|
927
|
-
//
|
|
928
|
-
//
|
|
929
|
-
//
|
|
930
|
-
// (checksum or lowercase), so an exact match
|
|
931
|
-
|
|
878
|
+
// One address listed twice for the same contract would violate the
|
|
879
|
+
// (chainId, address, contract) primary key of envio_addresses with an
|
|
880
|
+
// opaque Postgres error — fail fast instead. Two contracts may share an
|
|
881
|
+
// address: each indexes it with its own events. parseAddress already
|
|
882
|
+
// canonicalizes casing (checksum or lowercase), so an exact match
|
|
883
|
+
// catches case variants too.
|
|
884
|
+
let seen = Utils.Set.make()
|
|
932
885
|
contracts->Array.forEach(contract => {
|
|
933
886
|
contract.addresses->Array.forEach(
|
|
934
887
|
address => {
|
|
935
888
|
let addressString = address->Address.toString
|
|
936
|
-
|
|
937
|
-
|
|
889
|
+
let key = contract.name ++ "-" ++ addressString
|
|
890
|
+
if seen->Utils.Set.has(key) {
|
|
938
891
|
JsError.throwWithMessage(
|
|
939
|
-
|
|
940
|
-
? `Address ${addressString} is listed multiple times for the contract ${contract.name} on chain ${chainId->ChainId.toString}. Please remove the duplicate from your config.`
|
|
941
|
-
: `Address ${addressString} on chain ${chainId->ChainId.toString} is configured for multiple contracts: ${existingContractName} and ${contract.name}. Indexing the same address with multiple contract definitions is not supported. Please define the events on a single contract definition instead.`,
|
|
892
|
+
`Address ${addressString} is listed multiple times for the contract ${contract.name} on chain ${chainId->ChainId.toString}. Please remove the duplicate from your config.`,
|
|
942
893
|
)
|
|
943
|
-
| None => contractNameByAddress->Dict.set(addressString, contract.name)
|
|
944
894
|
}
|
|
895
|
+
seen->Utils.Set.add(key)->ignore
|
|
945
896
|
},
|
|
946
897
|
)
|
|
947
898
|
})
|
|
@@ -1012,6 +963,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
1012
963
|
{
|
|
1013
964
|
name: chainName,
|
|
1014
965
|
id: chainId,
|
|
966
|
+
ecosystem: ecosystemName,
|
|
1015
967
|
startBlock: publicChainConfig["startBlock"],
|
|
1016
968
|
endBlock: ?publicChainConfig["endBlock"],
|
|
1017
969
|
maxReorgDepth: switch ecosystemName {
|
|
@@ -1066,8 +1018,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
1066
1018
|
->Option.getOr([])
|
|
1067
1019
|
->parseEntitiesFromJson(~enumConfigsByName, ~globalStorage, ~defaultCrossChain)
|
|
1068
1020
|
|
|
1069
|
-
let allEntities = userEntities->Array.concat([EnvioAddresses.entityConfig])
|
|
1070
|
-
|
|
1071
1021
|
// Keyed by the capitalized entity name to match the handler-context
|
|
1072
1022
|
// accessor (`context.Pool_snapshots`) the generated types expose, while
|
|
1073
1023
|
// entityConfig.name stays the original schema name used for the physical
|
|
@@ -1104,6 +1054,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
1104
1054
|
storage: globalStorage,
|
|
1105
1055
|
chainIdMode: publicConfig["chainIdMode"]->Option.getOr(Int32),
|
|
1106
1056
|
chainMap,
|
|
1057
|
+
contractMapping: contractMappingOf(~chainConfigs=chains),
|
|
1107
1058
|
defaultChain: chains->Array.get(0),
|
|
1108
1059
|
enableRawEvents: publicConfig["rawEvents"]->Option.getOr(false),
|
|
1109
1060
|
ecosystem,
|
|
@@ -1115,7 +1066,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
1115
1066
|
isDev: publicConfig["isDev"]->Option.getOr(false),
|
|
1116
1067
|
userEntitiesByName,
|
|
1117
1068
|
userEntities,
|
|
1118
|
-
allEntities,
|
|
1119
1069
|
allEnums,
|
|
1120
1070
|
}
|
|
1121
1071
|
}
|