envio 3.13.0-rc.0 → 3.14.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/bin.mjs +10 -1
- package/index.d.ts +11 -0
- package/package.json +8 -20
- package/rescript.json +1 -4
- package/src/BatchProcessing.res +0 -2
- package/src/ChainState.res +39 -25
- package/src/ChainState.res.mjs +26 -23
- package/src/ChainState.resi +1 -2
- package/src/Config.res +69 -100
- package/src/Config.res.mjs +50 -63
- package/src/Core.res +46 -6
- package/src/Core.res.mjs +41 -4
- package/src/CrossChainState.res +13 -6
- package/src/CrossChainState.res.mjs +17 -4
- package/src/EventConfigBuilder.res +4 -10
- package/src/EventConfigBuilder.res.mjs +1 -3
- package/src/ExitOnCaughtUp.res +5 -1
- package/src/ExitOnCaughtUp.res.mjs +8 -3
- package/src/FinalizeBackfill.res +16 -10
- package/src/FinalizeBackfill.res.mjs +16 -5
- package/src/HandlerLoader.res +74 -32
- package/src/HandlerLoader.res.mjs +69 -23
- package/src/HandlerTypeCheck.mjs +14 -0
- package/src/HandlerTypeCheckWorker.mjs +68 -0
- package/src/Internal.res +1 -1
- package/src/Main.res +17 -12
- package/src/Main.res.mjs +9 -3
- package/src/NodeVersion.mjs +13 -0
- package/src/Persistence.res +79 -38
- package/src/Persistence.res.mjs +41 -10
- package/src/PgStorage.res +62 -34
- package/src/PgStorage.res.mjs +65 -31
- package/src/ResumePlan.res +172 -0
- package/src/ResumePlan.res.mjs +122 -0
- package/src/Supervisor.res +8 -8
- package/src/Supervisor.res.mjs +6 -1
- package/src/TestIndexer.res +19 -6
- package/src/TestIndexer.res.mjs +5 -4
- package/src/TsModuleHooks.mjs +121 -0
- package/src/Utils.res +0 -8
- package/src/Worker.res +8 -0
- package/src/Worker.res.mjs +11 -0
- package/src/bindings/NodeJs.res +8 -7
- package/src/bindings/NodeJs.res.mjs +0 -3
- package/src/bindings/Pino.res +2 -2
- package/src/db/InternalTable.res +52 -2
- package/src/db/InternalTable.res.mjs +32 -3
- package/src/sources/FuelHyperSync.res +2 -0
- package/src/sources/FuelHyperSync.res.mjs +1 -0
- package/src/sources/FuelHyperSync.resi +1 -0
- package/src/sources/FuelHyperSyncClient.res +25 -8
- package/src/sources/FuelHyperSyncClient.res.mjs +8 -2
- package/src/sources/FuelHyperSyncSource.res +24 -22
- package/src/sources/FuelHyperSyncSource.res.mjs +18 -13
- package/src/tui/InitApi.res +85 -0
- package/src/tui/{components/CustomHooks.res.mjs → InitApi.res.mjs} +11 -64
- package/src/tui/Tui.res +142 -249
- package/src/tui/Tui.res.mjs +123 -332
- package/src/Js.shim.ts +0 -11
- package/src/bindings/DateFns.res +0 -74
- package/src/bindings/DateFns.res.mjs +0 -22
- package/src/sources/FuelSDK.res +0 -38
- package/src/sources/FuelSDK.res.mjs +0 -27
- package/src/sources/vendored-fuel-abi-coder.js +0 -1792
- package/src/tui/bindings/Ink.res +0 -369
- package/src/tui/bindings/Ink.res.mjs +0 -66
- package/src/tui/bindings/Style.res +0 -123
- package/src/tui/bindings/Style.res.mjs +0 -2
- package/src/tui/components/BufferedProgressBar.res +0 -40
- package/src/tui/components/BufferedProgressBar.res.mjs +0 -57
- package/src/tui/components/CustomHooks.res +0 -122
- package/src/tui/components/Messages.res +0 -40
- package/src/tui/components/Messages.res.mjs +0 -71
- package/src/tui/components/SyncETA.res +0 -179
- package/src/tui/components/SyncETA.res.mjs +0 -249
- package/src/tui/components/TuiData.res +0 -98
- package/src/tui/components/TuiData.res.mjs +0 -73
package/src/Config.res.mjs
CHANGED
|
@@ -18,7 +18,6 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
|
18
18
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
19
19
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
20
20
|
import * as ContractMapping from "./ContractMapping.res.mjs";
|
|
21
|
-
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
22
21
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
23
22
|
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
24
23
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -439,6 +438,7 @@ let publicConfigSchema = S$RescriptSchema.schema(s => ({
|
|
|
439
438
|
handlers: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
440
439
|
isDev: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
|
|
441
440
|
isolatedChains: s.m(S$RescriptSchema.option(S$RescriptSchema.array(ChainId.schema))),
|
|
441
|
+
projectFlags: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
442
442
|
fullBatchSize: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
|
|
443
443
|
rollbackOnReorg: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
|
|
444
444
|
saveFullHistory: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
|
|
@@ -495,6 +495,41 @@ function isolate(config, chainIds) {
|
|
|
495
495
|
return newrecord;
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
+
let commandFields = [
|
|
499
|
+
"isDev",
|
|
500
|
+
"isolatedChains",
|
|
501
|
+
"projectFlags"
|
|
502
|
+
];
|
|
503
|
+
|
|
504
|
+
function withProjectFlags(command, config) {
|
|
505
|
+
let flags = config.projectFlags;
|
|
506
|
+
if (flags === "") {
|
|
507
|
+
return command;
|
|
508
|
+
} else {
|
|
509
|
+
return command + ` ` + flags;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
let ecosystemFields = [
|
|
514
|
+
"evm",
|
|
515
|
+
"fuel",
|
|
516
|
+
"svm"
|
|
517
|
+
];
|
|
518
|
+
|
|
519
|
+
function toEnvioInfo(publicConfigJson) {
|
|
520
|
+
let envioInfo = JSON.parse(JSON.stringify(publicConfigJson));
|
|
521
|
+
if (typeof envioInfo === "object" && envioInfo !== null && !Array.isArray(envioInfo)) {
|
|
522
|
+
commandFields.forEach(field => Utils.Dict.deleteInPlace(envioInfo, field));
|
|
523
|
+
ecosystemFields.forEach(ecosystem => {
|
|
524
|
+
let match = envioInfo[ecosystem];
|
|
525
|
+
if (typeof match === "object" && match !== null && !Array.isArray(match)) {
|
|
526
|
+
return Utils.Dict.deleteInPlace(match, "chains");
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return envioInfo;
|
|
531
|
+
}
|
|
532
|
+
|
|
498
533
|
function fromPublic(publicConfigJson) {
|
|
499
534
|
let publicConfig;
|
|
500
535
|
try {
|
|
@@ -801,7 +836,9 @@ function fromPublic(publicConfigJson) {
|
|
|
801
836
|
let config_enableRawEvents = Stdlib_Option.getOr(publicConfig.rawEvents, false);
|
|
802
837
|
let config_batchSize = Stdlib_Option.getOr(publicConfig.fullBatchSize, 5000);
|
|
803
838
|
let config_isDev = Stdlib_Option.getOr(publicConfig.isDev, false);
|
|
839
|
+
let config_projectFlags = Stdlib_Option.getOr(publicConfig.projectFlags, "");
|
|
804
840
|
let config_checkpointSequence = CheckpointSequence.fromEntities(userEntities);
|
|
841
|
+
let config_envioInfo = toEnvioInfo(publicConfigJson);
|
|
805
842
|
let config = {
|
|
806
843
|
name: config_name,
|
|
807
844
|
description: config_description,
|
|
@@ -823,11 +860,13 @@ function fromPublic(publicConfigJson) {
|
|
|
823
860
|
reorgThresholdReadyTolerance: 100,
|
|
824
861
|
lowercaseAddresses: lowercaseAddresses,
|
|
825
862
|
isDev: config_isDev,
|
|
863
|
+
projectFlags: config_projectFlags,
|
|
826
864
|
isolated: false,
|
|
827
865
|
userEntitiesByName: userEntitiesByName,
|
|
828
866
|
userEntities: userEntities,
|
|
829
867
|
allEnums: allEnums,
|
|
830
|
-
checkpointSequence: config_checkpointSequence
|
|
868
|
+
checkpointSequence: config_checkpointSequence,
|
|
869
|
+
envioInfo: config_envioInfo
|
|
831
870
|
};
|
|
832
871
|
let chainIds = publicConfig.isolatedChains;
|
|
833
872
|
if (chainIds !== undefined) {
|
|
@@ -933,44 +972,6 @@ function getPublicConfigJson() {
|
|
|
933
972
|
}
|
|
934
973
|
}
|
|
935
974
|
|
|
936
|
-
function stripSensitiveData(json) {
|
|
937
|
-
let cloned = JSON.parse(JSON.stringify(json));
|
|
938
|
-
let stripChains = ecosystem => {
|
|
939
|
-
if (ecosystem === undefined) {
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
942
|
-
if (typeof ecosystem !== "object" || ecosystem === null || Array.isArray(ecosystem)) {
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
let match = ecosystem["chains"];
|
|
946
|
-
if (match === undefined) {
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
if (typeof match !== "object" || match === null || Array.isArray(match)) {
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
Object.values(match).forEach(chainJson => {
|
|
953
|
-
if (typeof chainJson !== "object" || chainJson === null || Array.isArray(chainJson)) {
|
|
954
|
-
return;
|
|
955
|
-
}
|
|
956
|
-
Utils.Dict.deleteInPlace(chainJson, "rpcs");
|
|
957
|
-
Utils.Dict.deleteInPlace(chainJson, "hypersync");
|
|
958
|
-
});
|
|
959
|
-
};
|
|
960
|
-
if (typeof cloned === "object" && cloned !== null && !Array.isArray(cloned)) {
|
|
961
|
-
Utils.Dict.deleteInPlace(cloned, "isDev");
|
|
962
|
-
Utils.Dict.deleteInPlace(cloned, "isolatedChains");
|
|
963
|
-
stripChains(cloned["evm"]);
|
|
964
|
-
stripChains(cloned["fuel"]);
|
|
965
|
-
stripChains(cloned["svm"]);
|
|
966
|
-
}
|
|
967
|
-
return cloned;
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
function envioInfo() {
|
|
971
|
-
return stripSensitiveData(getPublicConfigJson());
|
|
972
|
-
}
|
|
973
|
-
|
|
974
975
|
function canonicalJson(json) {
|
|
975
976
|
if (Array.isArray(json)) {
|
|
976
977
|
return json.map(canonicalJson);
|
|
@@ -1088,7 +1089,8 @@ function diffPaths(stored, current) {
|
|
|
1088
1089
|
[
|
|
1089
1090
|
"evm",
|
|
1090
1091
|
"fuel",
|
|
1091
|
-
"svm"
|
|
1092
|
+
"svm",
|
|
1093
|
+
"chains"
|
|
1092
1094
|
],
|
|
1093
1095
|
["entities"]
|
|
1094
1096
|
];
|
|
@@ -1113,10 +1115,7 @@ function diffPaths(stored, current) {
|
|
|
1113
1115
|
return acc;
|
|
1114
1116
|
}
|
|
1115
1117
|
|
|
1116
|
-
function
|
|
1117
|
-
if (changedPaths.length === 0) {
|
|
1118
|
-
return;
|
|
1119
|
-
}
|
|
1118
|
+
function incompatibleMessage(changedPaths, resetCommand, runCommand, hasClickhouse) {
|
|
1120
1119
|
let bullets = changedPaths.map(p => ` - ` + p).join("\n");
|
|
1121
1120
|
let option1 = "Revert the changes above";
|
|
1122
1121
|
let padTo = (s, col) => s + " ".repeat(Math.max(col - s.length | 0, 1));
|
|
@@ -1128,20 +1127,7 @@ function throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhou
|
|
|
1128
1127
|
} else {
|
|
1129
1128
|
option3 = "";
|
|
1130
1129
|
}
|
|
1131
|
-
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
function throwIfResumeIncompatible(storedEnvioInfo, storedContractMapping, envioInfo, contractMapping, resetCommand, runCommand) {
|
|
1135
|
-
let changedPaths = storedEnvioInfo !== undefined ? diffPaths(storedEnvioInfo, envioInfo) : ["storage was initialized by an older envio version"];
|
|
1136
|
-
let changedPaths$1 = ContractMapping.isEqual(storedContractMapping, contractMapping) ? changedPaths : changedPaths.concat(["contracts"]);
|
|
1137
|
-
let hasClickhouse;
|
|
1138
|
-
if (typeof envioInfo === "object" && envioInfo !== null && !Array.isArray(envioInfo)) {
|
|
1139
|
-
let match = envioInfo["storage"];
|
|
1140
|
-
hasClickhouse = typeof match === "object" && match !== null && !Array.isArray(match) ? Primitive_object.equal(match["clickhouse"], true) : false;
|
|
1141
|
-
} else {
|
|
1142
|
-
hasClickhouse = false;
|
|
1143
|
-
}
|
|
1144
|
-
throwIfIncompatible(changedPaths$1, resetCommand, runCommand, hasClickhouse);
|
|
1130
|
+
return `The following config changes are incompatible with the existing indexer data:\n\n` + bullets + `\n\nPick one:\n 1. ` + padTo(option1, col) + `# resume indexing where it left off\n 2. ` + padTo(resetCommand, col) + `# delete all indexed data and start over` + option3;
|
|
1145
1131
|
}
|
|
1146
1132
|
|
|
1147
1133
|
function load() {
|
|
@@ -1195,6 +1181,10 @@ export {
|
|
|
1195
1181
|
getChain,
|
|
1196
1182
|
isPerChain,
|
|
1197
1183
|
isolate,
|
|
1184
|
+
commandFields,
|
|
1185
|
+
withProjectFlags,
|
|
1186
|
+
ecosystemFields,
|
|
1187
|
+
toEnvioInfo,
|
|
1198
1188
|
fromPublic,
|
|
1199
1189
|
normalizeUserAddress,
|
|
1200
1190
|
normalizeSimulateAddress,
|
|
@@ -1202,12 +1192,9 @@ export {
|
|
|
1202
1192
|
prime,
|
|
1203
1193
|
withCommandFields,
|
|
1204
1194
|
getPublicConfigJson,
|
|
1205
|
-
stripSensitiveData,
|
|
1206
|
-
envioInfo,
|
|
1207
1195
|
canonicalJson,
|
|
1208
1196
|
diffPaths,
|
|
1209
|
-
|
|
1210
|
-
throwIfResumeIncompatible,
|
|
1197
|
+
incompatibleMessage,
|
|
1211
1198
|
load,
|
|
1212
1199
|
getPgUserEntities,
|
|
1213
1200
|
}
|
package/src/Core.res
CHANGED
|
@@ -12,6 +12,7 @@ type transactionStoreCtor
|
|
|
12
12
|
type blockStoreCtor
|
|
13
13
|
type clickHouseSinkCtor
|
|
14
14
|
type addressStoreCtor
|
|
15
|
+
type tuiCtor
|
|
15
16
|
// Test-only: a local HyperSync server, bound by MockHyperSyncServer in envio-tests.
|
|
16
17
|
type mockHyperSyncServerCtor
|
|
17
18
|
type fromUserApiOptions = {
|
|
@@ -33,6 +34,10 @@ type addon = {
|
|
|
33
34
|
isSvmPubkey: (~value: string) => bool,
|
|
34
35
|
fromUserApi: (string, fromUserApiOptions) => fromUserApiResult,
|
|
35
36
|
runCli: (~args: array<string>, ~envioPackageDir: Null.t<string>) => promise<Null.t<string>>,
|
|
37
|
+
loadTs: string => string,
|
|
38
|
+
tsCheckHandlerFormat: string => unit,
|
|
39
|
+
tsResolveCandidates: (string, Null.t<string>) => array<string>,
|
|
40
|
+
tsNotFoundCandidates: (string, Null.t<string>, string) => array<string>,
|
|
36
41
|
@as("EvmHyperSyncClient")
|
|
37
42
|
evmHyperSyncClient: evmHyperSyncClientCtor,
|
|
38
43
|
@as("EvmRpcClient")
|
|
@@ -49,6 +54,8 @@ type addon = {
|
|
|
49
54
|
addressStore: addressStoreCtor,
|
|
50
55
|
@as("ClickHouseSink")
|
|
51
56
|
clickHouseSink: clickHouseSinkCtor,
|
|
57
|
+
@as("Tui")
|
|
58
|
+
tui: tuiCtor,
|
|
52
59
|
@as("MockHyperSyncServer")
|
|
53
60
|
mockHyperSyncServer: mockHyperSyncServerCtor,
|
|
54
61
|
encodeAddresses: (~ecosystem: string, ~addresses: array<Address.t>) => array<NodeJs.Buffer.t>,
|
|
@@ -99,7 +106,7 @@ let callRequire: ({..}, string) => addon = %raw(`(req, id) => req(id)`)
|
|
|
99
106
|
let envioPackageDir = pathDirname(pathDirname(fileURLToPath(importMetaUrl)))
|
|
100
107
|
|
|
101
108
|
// Runs `cargo build` on every invocation (like `cargo run`).
|
|
102
|
-
let loadDevAddon: ({..}, string) => addon = %raw(`function(req, envioDir) {
|
|
109
|
+
let loadDevAddon: ({..}, string) => Null.t<addon> = %raw(`function(req, envioDir) {
|
|
103
110
|
var cp = Nodechild_process;
|
|
104
111
|
var path = Nodepath;
|
|
105
112
|
var fs = Nodefs;
|
|
@@ -177,6 +184,22 @@ let loadDevAddon: ({..}, string) => addon = %raw(`function(req, envioDir) {
|
|
|
177
184
|
// `code`, and any other fields a diagnostic might rely on.
|
|
178
185
|
let rethrow: JsExn.t => 'a = %raw(`function(e) { throw e }`)
|
|
179
186
|
|
|
187
|
+
type packageJson = {version: string}
|
|
188
|
+
let requirePackageJson: ({..}, string) => packageJson = %raw(`(req, p) => req(p)`)
|
|
189
|
+
let devVersion = "0.0.1-dev"
|
|
190
|
+
|
|
191
|
+
let isGlibc: unit => bool = %raw(`() => Boolean(process.report?.getReport().header.glibcVersionRuntime)`)
|
|
192
|
+
|
|
193
|
+
@val external npmUserAgent: option<string> = "process.env.npm_config_user_agent"
|
|
194
|
+
|
|
195
|
+
let addCommand = () =>
|
|
196
|
+
switch npmUserAgent {
|
|
197
|
+
| Some(ua) if ua->String.startsWith("pnpm/") => "pnpm add"
|
|
198
|
+
| Some(ua) if ua->String.startsWith("yarn/") => "yarn add"
|
|
199
|
+
| Some(ua) if ua->String.startsWith("bun/") => "bun add"
|
|
200
|
+
| _ => "npm install"
|
|
201
|
+
}
|
|
202
|
+
|
|
180
203
|
let loadAddon = () => {
|
|
181
204
|
let req = createRequire(importMetaUrl)
|
|
182
205
|
|
|
@@ -212,15 +235,32 @@ let loadAddon = () => {
|
|
|
212
235
|
switch tryRequire(0) {
|
|
213
236
|
| Some(addon) => addon
|
|
214
237
|
| None =>
|
|
215
|
-
|
|
216
|
-
|
|
238
|
+
let version = requirePackageJson(req, "../package.json").version
|
|
239
|
+
// Publishing stamps the real version, so only a monorepo checkout (or a
|
|
240
|
+
// `file:` link to one) can have a dev build to fall back to. Skipping it
|
|
241
|
+
// spares published installs a `pnpm list` spawn before the error below.
|
|
242
|
+
let devAddon = if version === devVersion {
|
|
243
|
+
loadDevAddon(req, envioPackageDir)->Null.toOption
|
|
244
|
+
} else {
|
|
245
|
+
None
|
|
246
|
+
}
|
|
247
|
+
switch devAddon {
|
|
217
248
|
| Some(addon) => addon
|
|
218
249
|
| None =>
|
|
219
250
|
let host = `${processPlatform}-${processArch}`
|
|
220
|
-
let msg =
|
|
251
|
+
let msg = switch candidates {
|
|
252
|
+
| []
|
|
253
|
+
if processPlatform === "win32" => `envio doesn't run natively on Windows. Use WSL 2 instead: https://learn.microsoft.com/windows/wsl/install`
|
|
254
|
+
| [] =>
|
|
221
255
|
`envio doesn't support ${host}. Supported: linux-x64 (glibc/musl), linux-arm64, darwin-x64, darwin-arm64.`
|
|
222
|
-
|
|
223
|
-
|
|
256
|
+
| _ =>
|
|
257
|
+
let pkg = if processPlatform === "linux" && processArch === "x64" && !isGlibc() {
|
|
258
|
+
`envio-linux-x64-musl`
|
|
259
|
+
} else {
|
|
260
|
+
candidates->Array.getUnsafe(0)
|
|
261
|
+
}
|
|
262
|
+
`envio's native binary for ${host} isn't installed (package "${pkg}"). This happens when optional dependencies are skipped (--omit=optional, --no-optional) or the lockfile was generated on another platform.
|
|
263
|
+
Reinstall dependencies, or add the package explicitly: ${addCommand()} ${pkg}@${version}`
|
|
224
264
|
}
|
|
225
265
|
JsError.throwWithMessage(msg)
|
|
226
266
|
}
|
package/src/Core.res.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import * as Nodepath from "node:path";
|
|
|
6
6
|
import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
|
|
7
7
|
import * as Nodemodule from "node:module";
|
|
8
8
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
9
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
9
10
|
import * as Nodechild_process from "node:child_process";
|
|
10
11
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
11
12
|
|
|
@@ -97,6 +98,29 @@ let loadDevAddon = (function(req, envioDir) {
|
|
|
97
98
|
|
|
98
99
|
let rethrow = (function(e) { throw e });
|
|
99
100
|
|
|
101
|
+
let requirePackageJson = ((req, p) => req(p));
|
|
102
|
+
|
|
103
|
+
let devVersion = "0.0.1-dev";
|
|
104
|
+
|
|
105
|
+
let isGlibc = (() => Boolean(process.report?.getReport().header.glibcVersionRuntime));
|
|
106
|
+
|
|
107
|
+
function addCommand() {
|
|
108
|
+
let ua = process.env.npm_config_user_agent;
|
|
109
|
+
if (ua !== undefined) {
|
|
110
|
+
if (ua.startsWith("pnpm/")) {
|
|
111
|
+
return "pnpm add";
|
|
112
|
+
} else if (ua.startsWith("yarn/")) {
|
|
113
|
+
return "yarn add";
|
|
114
|
+
} else if (ua.startsWith("bun/")) {
|
|
115
|
+
return "bun add";
|
|
116
|
+
} else {
|
|
117
|
+
return "npm install";
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
return "npm install";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
100
124
|
function loadAddon() {
|
|
101
125
|
let req = Nodemodule.createRequire(import.meta.url);
|
|
102
126
|
let match = process.platform;
|
|
@@ -161,12 +185,21 @@ function loadAddon() {
|
|
|
161
185
|
if (addon !== undefined) {
|
|
162
186
|
return addon;
|
|
163
187
|
}
|
|
164
|
-
let
|
|
165
|
-
|
|
166
|
-
|
|
188
|
+
let version = requirePackageJson(req, "../package.json").version;
|
|
189
|
+
let devAddon = version === devVersion ? Primitive_option.fromNull(loadDevAddon(req, envioPackageDir)) : undefined;
|
|
190
|
+
if (devAddon !== undefined) {
|
|
191
|
+
return devAddon;
|
|
167
192
|
}
|
|
168
193
|
let host = process.platform + `-` + process.arch;
|
|
169
|
-
|
|
194
|
+
let tmp;
|
|
195
|
+
if (candidates.length !== 0) {
|
|
196
|
+
let pkg = process.platform === "linux" && process.arch === "x64" && !isGlibc() ? `envio-linux-x64-musl` : candidates[0];
|
|
197
|
+
tmp = `envio's native binary for ` + host + ` isn't installed (package "` + pkg + `"). This happens when optional dependencies are skipped (--omit=optional, --no-optional) or the lockfile was generated on another platform.
|
|
198
|
+
Reinstall dependencies, or add the package explicitly: ` + addCommand() + ` ` + pkg + `@` + version;
|
|
199
|
+
} else {
|
|
200
|
+
tmp = process.platform === "win32" ? `envio doesn't run natively on Windows. Use WSL 2 instead: https://learn.microsoft.com/windows/wsl/install` : `envio doesn't support ` + host + `. Supported: linux-x64 (glibc/musl), linux-arm64, darwin-x64, darwin-arm64.`;
|
|
201
|
+
}
|
|
202
|
+
return Stdlib_JsError.throwWithMessage(tmp);
|
|
170
203
|
}
|
|
171
204
|
|
|
172
205
|
let addonRef = {
|
|
@@ -211,6 +244,10 @@ export {
|
|
|
211
244
|
envioPackageDir,
|
|
212
245
|
loadDevAddon,
|
|
213
246
|
rethrow,
|
|
247
|
+
requirePackageJson,
|
|
248
|
+
devVersion,
|
|
249
|
+
isGlibc,
|
|
250
|
+
addCommand,
|
|
214
251
|
loadAddon,
|
|
215
252
|
addonRef,
|
|
216
253
|
getAddon,
|
package/src/CrossChainState.res
CHANGED
|
@@ -199,7 +199,7 @@ let applyBatchProgress = (crossChainState: t, ~batch: Batch.t, ~blockTimestampNa
|
|
|
199
199
|
for i in 0 to chainIds->Array.length - 1 {
|
|
200
200
|
let cs = crossChainState->getChainState(chainIds->Array.getUnsafe(i))
|
|
201
201
|
cs->ChainState.applyBatchProgress(~batch, ~blockTimestampName)
|
|
202
|
-
if !(cs->ChainState.
|
|
202
|
+
if !(cs->ChainState.hasCaughtUp) {
|
|
203
203
|
everyChainCaughtUp := false
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -254,7 +254,7 @@ let markCaughtUpOnResume = (crossChainState: t) => {
|
|
|
254
254
|
let everyChainCaughtUp = ref(crossChainState.chainIds->Array.length > 0)
|
|
255
255
|
for i in 0 to crossChainState.chainIds->Array.length - 1 {
|
|
256
256
|
let cs = crossChainState->getChainState(crossChainState.chainIds->Array.getUnsafe(i))
|
|
257
|
-
if !(cs->ChainState.
|
|
257
|
+
if !(cs->ChainState.hasCaughtUp) {
|
|
258
258
|
everyChainCaughtUp := false
|
|
259
259
|
}
|
|
260
260
|
}
|
|
@@ -284,11 +284,19 @@ let markReady = (crossChainState: t, ~readyAt) => {
|
|
|
284
284
|
crossChainState.isRealtime = true
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
// What a caught-up chain is waiting on before its process can finalize: the run
|
|
288
|
+
// holding the process back, or another chain it drives still behind. Read when
|
|
289
|
+
// the chain speaks, so "waiting" is said only while it is true.
|
|
290
|
+
let isWaitingOnOthers = (crossChainState: t, cs: ChainState.t) =>
|
|
291
|
+
crossChainState.holdRealtime ||
|
|
292
|
+
crossChainState.chainStates
|
|
293
|
+
->Dict.valuesToArray
|
|
294
|
+
->Array.some(other => other !== cs && !(other->ChainState.hasCaughtUp))
|
|
295
|
+
|
|
287
296
|
// Each chain that has just finished indexing, said once, by the chain it is
|
|
288
297
|
// about — so a chain that finishes early says so then, rather than when the
|
|
289
298
|
// last chain in its process catches up.
|
|
290
|
-
let reportFinished = (crossChainState: t) =>
|
|
291
|
-
let waitingOnOthers = crossChainState.holdRealtime || crossChainState.chainIds->Array.length > 1
|
|
299
|
+
let reportFinished = (crossChainState: t) =>
|
|
292
300
|
crossChainState.chainStates
|
|
293
301
|
->Dict.valuesToArray
|
|
294
302
|
->Array.forEach(cs =>
|
|
@@ -301,7 +309,7 @@ let reportFinished = (crossChainState: t) => {
|
|
|
301
309
|
cs
|
|
302
310
|
->ChainState.logger
|
|
303
311
|
->Logging.childInfo({
|
|
304
|
-
"msg":
|
|
312
|
+
"msg": crossChainState->isWaitingOnOthers(cs)
|
|
305
313
|
? "Finished backfill. Waiting for the other chains."
|
|
306
314
|
: "Finished backfill.",
|
|
307
315
|
"block": block,
|
|
@@ -309,7 +317,6 @@ let reportFinished = (crossChainState: t) => {
|
|
|
309
317
|
| None => ()
|
|
310
318
|
}
|
|
311
319
|
)
|
|
312
|
-
}
|
|
313
320
|
|
|
314
321
|
// --- Fetch control. ---
|
|
315
322
|
|
|
@@ -141,7 +141,7 @@ function applyBatchProgress(crossChainState, batch, blockTimestampName) {
|
|
|
141
141
|
for (let i = 0, i_finish = chainIds.length; i < i_finish; ++i) {
|
|
142
142
|
let cs = crossChainState.chainStates[chainIds[i]];
|
|
143
143
|
ChainState.applyBatchProgress(cs, batch, blockTimestampName);
|
|
144
|
-
if (!
|
|
144
|
+
if (!ChainState.hasCaughtUp(cs)) {
|
|
145
145
|
everyChainCaughtUp = false;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
@@ -169,7 +169,7 @@ function markCaughtUpOnResume(crossChainState) {
|
|
|
169
169
|
let everyChainCaughtUp = crossChainState.chainIds.length !== 0;
|
|
170
170
|
for (let i = 0, i_finish = crossChainState.chainIds.length; i < i_finish; ++i) {
|
|
171
171
|
let cs = crossChainState.chainStates[crossChainState.chainIds[i]];
|
|
172
|
-
if (!ChainState.
|
|
172
|
+
if (!ChainState.hasCaughtUp(cs)) {
|
|
173
173
|
everyChainCaughtUp = false;
|
|
174
174
|
}
|
|
175
175
|
}
|
|
@@ -191,8 +191,21 @@ function markReady(crossChainState, readyAt) {
|
|
|
191
191
|
crossChainState.isRealtime = true;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
function isWaitingOnOthers(crossChainState, cs) {
|
|
195
|
+
if (crossChainState.holdRealtime) {
|
|
196
|
+
return true;
|
|
197
|
+
} else {
|
|
198
|
+
return Object.values(crossChainState.chainStates).some(other => {
|
|
199
|
+
if (other !== cs) {
|
|
200
|
+
return !ChainState.hasCaughtUp(other);
|
|
201
|
+
} else {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
194
208
|
function reportFinished(crossChainState) {
|
|
195
|
-
let waitingOnOthers = crossChainState.holdRealtime || crossChainState.chainIds.length > 1;
|
|
196
209
|
Object.values(crossChainState.chainStates).forEach(cs => {
|
|
197
210
|
let match = ChainState.takeFinished(cs);
|
|
198
211
|
if (match !== undefined) {
|
|
@@ -203,7 +216,7 @@ function reportFinished(crossChainState) {
|
|
|
203
216
|
});
|
|
204
217
|
} else {
|
|
205
218
|
return Logging.childInfo(ChainState.logger(cs), {
|
|
206
|
-
msg:
|
|
219
|
+
msg: isWaitingOnOthers(crossChainState, cs) ? "Finished backfill. Waiting for the other chains." : "Finished backfill.",
|
|
207
220
|
block: match._0
|
|
208
221
|
});
|
|
209
222
|
}
|
|
@@ -343,7 +343,7 @@ let validateFieldsShapeOrThrow = (
|
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
let selectionList = (fields: unknown, key: string): option<array<string>> =>
|
|
346
|
-
switch
|
|
346
|
+
switch fields->(Utils.magic: unknown => dict<unknown>)->Dict.get(key) {
|
|
347
347
|
| None => None
|
|
348
348
|
| Some(value) => Some(value->(Utils.magic: unknown => array<string>))
|
|
349
349
|
}
|
|
@@ -371,8 +371,8 @@ let parseFieldsOrThrow = (
|
|
|
371
371
|
if !(valid->Utils.Set.has(name)) {
|
|
372
372
|
JsError.throwWithMessage(
|
|
373
373
|
`Invalid "${name}" field in the fields.${kind} option of ${registration}. Valid ${kind} fields: ${Utils.Array.quotedJoin(
|
|
374
|
-
|
|
375
|
-
|
|
374
|
+
valid->Utils.Set.toArray,
|
|
375
|
+
)}.`,
|
|
376
376
|
)
|
|
377
377
|
}
|
|
378
378
|
if seen->Utils.Set.has(name) {
|
|
@@ -858,13 +858,7 @@ let buildFuelEventConfig = (
|
|
|
858
858
|
~rawAbi: JSON.t,
|
|
859
859
|
): Internal.fuelEventConfig => {
|
|
860
860
|
let fuelKind = switch kind {
|
|
861
|
-
| "logData" =>
|
|
862
|
-
// Transpile raw Fuel ABI to the format expected by the vendored ABI coder
|
|
863
|
-
let abi = FuelSDK.transpileAbi(rawAbi)
|
|
864
|
-
Internal.LogData({
|
|
865
|
-
logId: sighash,
|
|
866
|
-
decode: FuelSDK.Receipt.getLogDataDecoder(~abi, ~logId=sighash),
|
|
867
|
-
})
|
|
861
|
+
| "logData" => Internal.LogData({logId: sighash, abi: rawAbi})
|
|
868
862
|
| "mint" => Mint
|
|
869
863
|
| "burn" => Burn
|
|
870
864
|
| "transfer" => Transfer
|
|
@@ -6,7 +6,6 @@ import * as Core from "./Core.res.mjs";
|
|
|
6
6
|
import * as Fuel from "./sources/Fuel.res.mjs";
|
|
7
7
|
import * as Utils from "./Utils.res.mjs";
|
|
8
8
|
import * as Address from "./Address.res.mjs";
|
|
9
|
-
import * as FuelSDK from "./sources/FuelSDK.res.mjs";
|
|
10
9
|
import * as Internal from "./Internal.res.mjs";
|
|
11
10
|
import * as LogSelection from "./LogSelection.res.mjs";
|
|
12
11
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
@@ -590,11 +589,10 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
|
|
|
590
589
|
fuelKind = "Call";
|
|
591
590
|
break;
|
|
592
591
|
case "logData" :
|
|
593
|
-
let abi = FuelSDK.transpileAbi(rawAbi);
|
|
594
592
|
fuelKind = {
|
|
595
593
|
TAG: "LogData",
|
|
596
594
|
logId: sighash,
|
|
597
|
-
|
|
595
|
+
abi: rawAbi
|
|
598
596
|
};
|
|
599
597
|
break;
|
|
600
598
|
case "mint" :
|
package/src/ExitOnCaughtUp.res
CHANGED
|
@@ -14,7 +14,11 @@ let run = async (state: IndexerState.t) => {
|
|
|
14
14
|
| Some(onExit) => onExit()
|
|
15
15
|
| None =>
|
|
16
16
|
Logging.info("Exiting with success")
|
|
17
|
-
|
|
17
|
+
if Worker.isEnabled {
|
|
18
|
+
Worker.exitAfterReporting(~metrics=state->IndexerState.toMetrics)
|
|
19
|
+
} else {
|
|
20
|
+
NodeJs.process->NodeJs.exitWithCode(Success)
|
|
21
|
+
}
|
|
18
22
|
}
|
|
19
23
|
| Some(message) => state->IndexerState.errorExit(ErrorHandling.make(Utils.Error.make(message)))
|
|
20
24
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Worker from "./Worker.res.mjs";
|
|
3
4
|
import * as Logging from "./Logging.res.mjs";
|
|
4
5
|
import * as Writing from "./Writing.res.mjs";
|
|
5
6
|
import * as Process from "process";
|
|
@@ -24,12 +25,16 @@ async function run(state) {
|
|
|
24
25
|
return onExit();
|
|
25
26
|
} else {
|
|
26
27
|
Logging.info("Exiting with success");
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
if (Worker.isEnabled) {
|
|
29
|
+
return Worker.exitAfterReporting(IndexerState.toMetrics(state));
|
|
30
|
+
} else {
|
|
31
|
+
Process.exit(0);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
export {
|
|
33
38
|
run,
|
|
34
39
|
}
|
|
35
|
-
/*
|
|
40
|
+
/* Worker Not a pure module */
|
package/src/FinalizeBackfill.res
CHANGED
|
@@ -11,15 +11,25 @@
|
|
|
11
11
|
// `envio start --chain` process is indexing and never waits on one.
|
|
12
12
|
|
|
13
13
|
let runOnce = async (state: IndexerState.t) => {
|
|
14
|
+
let chainIds = state->IndexerState.crossChainState->CrossChainState.chainIds
|
|
15
|
+
|
|
16
|
+
// Whatever brought the process here — a batch, a tick that progressed
|
|
17
|
+
// nothing, a supervisor's release — its chains say where they finished
|
|
18
|
+
// before it says what it does about that. Said here rather than left to each
|
|
19
|
+
// caller to order: a chain that has already spoken says nothing again.
|
|
20
|
+
state->IndexerState.reportFinished
|
|
21
|
+
|
|
14
22
|
// Said by the process rather than by each of its chains: the indexes are one
|
|
15
23
|
// build over the tables, and the pause is the whole process's. A chain has
|
|
16
24
|
// already said it caught up, and says it is ready once this commits. The
|
|
17
25
|
// chains are named because the pause is theirs, and a split run has a process
|
|
18
|
-
// saying this for each part of it
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
})
|
|
26
|
+
// saying this for each part of it — one of them, for a process driving a
|
|
27
|
+
// single chain.
|
|
28
|
+
let msg = "Building database indexes. Indexing is paused until they are ready, which can take a while on a large database."
|
|
29
|
+
switch chainIds {
|
|
30
|
+
| [chainId] => Logging.info({"msg": msg, "chainId": chainId})
|
|
31
|
+
| chainIds => Logging.info({"msg": msg, "chainIds": chainIds})
|
|
32
|
+
}
|
|
23
33
|
|
|
24
34
|
await Writing.flush(state)
|
|
25
35
|
|
|
@@ -30,11 +40,7 @@ let runOnce = async (state: IndexerState.t) => {
|
|
|
30
40
|
let storage = persistence->Persistence.getInitializedStorageOrThrow
|
|
31
41
|
let readyAt = Date.make()
|
|
32
42
|
|
|
33
|
-
await storage.finalizeBackfill(
|
|
34
|
-
~entities=persistence.allEntities,
|
|
35
|
-
~chainIds=state->IndexerState.crossChainState->CrossChainState.chainIds,
|
|
36
|
-
~readyAt,
|
|
37
|
-
)
|
|
43
|
+
await storage.finalizeBackfill(~entities=persistence.allEntities, ~chainIds, ~readyAt)
|
|
38
44
|
|
|
39
45
|
// Only after the commit: in-memory readiness must never run ahead of the
|
|
40
46
|
// `ready_at` a restart would read back.
|
|
@@ -7,10 +7,21 @@ import * as IndexerState from "./IndexerState.res.mjs";
|
|
|
7
7
|
import * as CrossChainState from "./CrossChainState.res.mjs";
|
|
8
8
|
|
|
9
9
|
async function runOnce(state) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
let chainIds = CrossChainState.chainIds(IndexerState.crossChainState(state));
|
|
11
|
+
IndexerState.reportFinished(state);
|
|
12
|
+
let msg = "Building database indexes. Indexing is paused until they are ready, which can take a while on a large database.";
|
|
13
|
+
if (chainIds.length !== 1) {
|
|
14
|
+
Logging.info({
|
|
15
|
+
msg: msg,
|
|
16
|
+
chainIds: chainIds
|
|
17
|
+
});
|
|
18
|
+
} else {
|
|
19
|
+
let chainId = chainIds[0];
|
|
20
|
+
Logging.info({
|
|
21
|
+
msg: msg,
|
|
22
|
+
chainId: chainId
|
|
23
|
+
});
|
|
24
|
+
}
|
|
14
25
|
await Writing.flush(state);
|
|
15
26
|
if (IndexerState.hasFailedWrite(state)) {
|
|
16
27
|
return;
|
|
@@ -18,7 +29,7 @@ async function runOnce(state) {
|
|
|
18
29
|
let persistence = IndexerState.persistence(state);
|
|
19
30
|
let storage = Persistence.getInitializedStorageOrThrow(persistence);
|
|
20
31
|
let readyAt = new Date();
|
|
21
|
-
await storage.finalizeBackfill(persistence.allEntities,
|
|
32
|
+
await storage.finalizeBackfill(persistence.allEntities, chainIds, readyAt);
|
|
22
33
|
return IndexerState.markReady(state, readyAt);
|
|
23
34
|
}
|
|
24
35
|
|