envio 3.0.1 → 3.0.2-svm-alpha.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/evm.schema.json +8 -8
- package/fuel.schema.json +12 -12
- package/index.d.ts +155 -1
- package/package.json +6 -7
- package/src/ChainFetcher.res +25 -1
- package/src/ChainFetcher.res.mjs +19 -1
- package/src/Config.res +156 -94
- package/src/Config.res.mjs +60 -97
- package/src/Core.res +32 -0
- package/src/Env.res.mjs +1 -2
- package/src/Envio.res +94 -0
- package/src/EventConfigBuilder.res +50 -0
- package/src/EventConfigBuilder.res.mjs +31 -0
- package/src/HandlerLoader.res +12 -1
- package/src/HandlerLoader.res.mjs +6 -1
- package/src/Internal.res +38 -0
- package/src/Main.res +53 -3
- package/src/Main.res.mjs +34 -2
- package/src/Persistence.res +2 -17
- package/src/Persistence.res.mjs +2 -14
- package/src/SimulateItems.res +23 -10
- package/src/SimulateItems.res.mjs +21 -6
- package/src/SvmTypes.res +9 -0
- package/src/SvmTypes.res.mjs +14 -0
- package/src/sources/EventRouter.res +65 -0
- package/src/sources/EventRouter.res.mjs +43 -0
- package/src/sources/HyperSyncClient.res +30 -157
- package/src/sources/HyperSyncClient.res.mjs +20 -6
- package/src/sources/HyperSyncSolanaClient.res +227 -0
- package/src/sources/HyperSyncSolanaClient.res.mjs +25 -0
- package/src/sources/HyperSyncSolanaSource.res +515 -0
- package/src/sources/HyperSyncSolanaSource.res.mjs +441 -0
- package/src/sources/HyperSyncSource.res +5 -8
- package/src/sources/HyperSyncSource.res.mjs +1 -8
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/Svm.res +2 -2
- package/src/sources/Svm.res.mjs +3 -2
- package/src/tui/Tui.res +9 -2
- package/src/tui/Tui.res.mjs +19 -4
- package/src/tui/components/TuiData.res +3 -0
- package/svm.schema.json +345 -4
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Core from "../Core.res.mjs";
|
|
4
|
+
import * as Hrtime from "../bindings/Hrtime.res.mjs";
|
|
5
|
+
import * as Source from "./Source.res.mjs";
|
|
6
|
+
import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
|
|
7
|
+
import * as Prometheus from "../Prometheus.res.mjs";
|
|
8
|
+
import * as EventRouter from "./EventRouter.res.mjs";
|
|
9
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
10
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
11
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
12
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
13
|
+
import * as HyperSyncSolanaClient from "./HyperSyncSolanaClient.res.mjs";
|
|
14
|
+
|
|
15
|
+
let EventRoutingFailed = /* @__PURE__ */Primitive_exceptions.create("HyperSyncSolanaSource.EventRoutingFailed");
|
|
16
|
+
|
|
17
|
+
function buildInstructionSelections(eventConfigs) {
|
|
18
|
+
return Belt_Array.keepMap(eventConfigs, cfg => {
|
|
19
|
+
let programIdString = cfg.programId;
|
|
20
|
+
if (programIdString === "") {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let match = cfg.discriminator;
|
|
24
|
+
let match$1 = cfg.discriminatorByteLen;
|
|
25
|
+
let match$2;
|
|
26
|
+
if (match !== undefined) {
|
|
27
|
+
switch (match$1) {
|
|
28
|
+
case 1 :
|
|
29
|
+
match$2 = [
|
|
30
|
+
[match],
|
|
31
|
+
undefined,
|
|
32
|
+
undefined,
|
|
33
|
+
undefined
|
|
34
|
+
];
|
|
35
|
+
break;
|
|
36
|
+
case 2 :
|
|
37
|
+
match$2 = [
|
|
38
|
+
undefined,
|
|
39
|
+
[match],
|
|
40
|
+
undefined,
|
|
41
|
+
undefined
|
|
42
|
+
];
|
|
43
|
+
break;
|
|
44
|
+
case 4 :
|
|
45
|
+
match$2 = [
|
|
46
|
+
undefined,
|
|
47
|
+
undefined,
|
|
48
|
+
[match],
|
|
49
|
+
undefined
|
|
50
|
+
];
|
|
51
|
+
break;
|
|
52
|
+
case 8 :
|
|
53
|
+
match$2 = [
|
|
54
|
+
undefined,
|
|
55
|
+
undefined,
|
|
56
|
+
undefined,
|
|
57
|
+
[match]
|
|
58
|
+
];
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
match$2 = [
|
|
62
|
+
undefined,
|
|
63
|
+
undefined,
|
|
64
|
+
undefined,
|
|
65
|
+
undefined
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
match$2 = [
|
|
70
|
+
undefined,
|
|
71
|
+
undefined,
|
|
72
|
+
undefined,
|
|
73
|
+
undefined
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
let accountFilters = cfg.accountFilters;
|
|
77
|
+
let a0 = Belt_Array.get(Belt_Array.keepMap(accountFilters, f => {
|
|
78
|
+
if (f.position === 0) {
|
|
79
|
+
return f.values;
|
|
80
|
+
}
|
|
81
|
+
}), 0);
|
|
82
|
+
let a1 = Belt_Array.get(Belt_Array.keepMap(accountFilters, f => {
|
|
83
|
+
if (f.position === 1) {
|
|
84
|
+
return f.values;
|
|
85
|
+
}
|
|
86
|
+
}), 0);
|
|
87
|
+
let a2 = Belt_Array.get(Belt_Array.keepMap(accountFilters, f => {
|
|
88
|
+
if (f.position === 2) {
|
|
89
|
+
return f.values;
|
|
90
|
+
}
|
|
91
|
+
}), 0);
|
|
92
|
+
let a3 = Belt_Array.get(Belt_Array.keepMap(accountFilters, f => {
|
|
93
|
+
if (f.position === 3) {
|
|
94
|
+
return f.values;
|
|
95
|
+
}
|
|
96
|
+
}), 0);
|
|
97
|
+
let a4 = Belt_Array.get(Belt_Array.keepMap(accountFilters, f => {
|
|
98
|
+
if (f.position === 4) {
|
|
99
|
+
return f.values;
|
|
100
|
+
}
|
|
101
|
+
}), 0);
|
|
102
|
+
let a5 = Belt_Array.get(Belt_Array.keepMap(accountFilters, f => {
|
|
103
|
+
if (f.position === 5) {
|
|
104
|
+
return f.values;
|
|
105
|
+
}
|
|
106
|
+
}), 0);
|
|
107
|
+
return {
|
|
108
|
+
programId: [programIdString],
|
|
109
|
+
d1: match$2[0],
|
|
110
|
+
d2: match$2[1],
|
|
111
|
+
d4: match$2[2],
|
|
112
|
+
d8: match$2[3],
|
|
113
|
+
a0: a0,
|
|
114
|
+
a1: a1,
|
|
115
|
+
a2: a2,
|
|
116
|
+
a3: a3,
|
|
117
|
+
a4: a4,
|
|
118
|
+
a5: a5,
|
|
119
|
+
isInner: cfg.isInner,
|
|
120
|
+
includeTransaction: cfg.includeTransaction,
|
|
121
|
+
includeLogs: cfg.includeLogs
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function synthLogIndex(instr) {
|
|
127
|
+
let tx = instr.transactionIndex;
|
|
128
|
+
let addrSum = Belt_Array.reduce(instr.instructionAddress, 0, (acc, n) => ((acc << 10) + n | 0) + 1 | 0);
|
|
129
|
+
return (tx << 16) + addrSum | 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function serializeInstructionAddress(addr) {
|
|
133
|
+
return addr.map(n => n.toString()).join(",");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function buildSchemaHandles(eventConfigs) {
|
|
137
|
+
let descriptorsByProgram = {};
|
|
138
|
+
Belt_Array.forEach(eventConfigs, ec => {
|
|
139
|
+
let programIdString = ec.programId;
|
|
140
|
+
if (programIdString === "") {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
let hasSchema = ec.accounts.length !== 0 || ec.args !== null;
|
|
144
|
+
let discriminator = Stdlib_Option.getOr(ec.discriminator, "");
|
|
145
|
+
if (!(hasSchema && discriminator !== "")) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
let existing = descriptorsByProgram[programIdString];
|
|
149
|
+
let descriptor = existing !== undefined ? Primitive_option.valFromOption(existing) : ({
|
|
150
|
+
programId: programIdString,
|
|
151
|
+
definedTypes: ec.definedTypes,
|
|
152
|
+
instructions: []
|
|
153
|
+
});
|
|
154
|
+
let instruction = {
|
|
155
|
+
name: ec.name,
|
|
156
|
+
discriminator: discriminator,
|
|
157
|
+
accounts: ec.accounts,
|
|
158
|
+
args: ec.args
|
|
159
|
+
};
|
|
160
|
+
descriptorsByProgram[programIdString] = {
|
|
161
|
+
programId: descriptor.programId,
|
|
162
|
+
definedTypes: descriptor.definedTypes,
|
|
163
|
+
instructions: descriptor.instructions.concat([instruction])
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
let handles = {};
|
|
167
|
+
Belt_Array.forEach(Object.entries(descriptorsByProgram), param => {
|
|
168
|
+
let json = JSON.stringify(param[1]);
|
|
169
|
+
let handle = Core.getAddon().registerProgramSchema(json);
|
|
170
|
+
handles[param[0]] = handle;
|
|
171
|
+
});
|
|
172
|
+
return handles;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function decodeIfPossible(instr, schemaHandlesByProgram) {
|
|
176
|
+
let handle = schemaHandlesByProgram[instr.programId];
|
|
177
|
+
if (handle === undefined) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
let decoded = Core.getAddon().decodeInstruction(handle, instr.data, instr.accounts);
|
|
181
|
+
if (decoded === null) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
let args;
|
|
185
|
+
try {
|
|
186
|
+
args = JSON.parse(decoded.argsJson);
|
|
187
|
+
} catch (exn) {
|
|
188
|
+
args = {};
|
|
189
|
+
}
|
|
190
|
+
let accounts;
|
|
191
|
+
try {
|
|
192
|
+
accounts = JSON.parse(decoded.accountsJson);
|
|
193
|
+
} catch (exn$1) {
|
|
194
|
+
accounts = {};
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
name: decoded.name,
|
|
198
|
+
args: args,
|
|
199
|
+
accounts: accounts,
|
|
200
|
+
extraAccounts: decoded.extraAccounts
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function toSvmInstruction(instr, schemaHandlesByProgram) {
|
|
205
|
+
return {
|
|
206
|
+
programId: instr.programId,
|
|
207
|
+
data: instr.data,
|
|
208
|
+
accounts: instr.accounts,
|
|
209
|
+
instructionAddress: instr.instructionAddress,
|
|
210
|
+
isInner: instr.isInner,
|
|
211
|
+
d1: instr.d1,
|
|
212
|
+
d2: instr.d2,
|
|
213
|
+
d4: instr.d4,
|
|
214
|
+
d8: instr.d8,
|
|
215
|
+
decoded: decodeIfPossible(instr, schemaHandlesByProgram)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function toSvmTransaction(tx) {
|
|
220
|
+
return {
|
|
221
|
+
signatures: tx.signatures,
|
|
222
|
+
feePayer: Stdlib_Option.map(tx.feePayer, prim => prim),
|
|
223
|
+
success: tx.success,
|
|
224
|
+
err: tx.err,
|
|
225
|
+
fee: Stdlib_Option.map(tx.fee, prim => BigInt(prim)),
|
|
226
|
+
computeUnitsConsumed: Stdlib_Option.map(tx.computeUnitsConsumed, prim => BigInt(prim)),
|
|
227
|
+
accountKeys: tx.accountKeys,
|
|
228
|
+
recentBlockhash: tx.recentBlockhash,
|
|
229
|
+
version: tx.version
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function probeRouter(router, programId, instr, byteLengthsDesc, contractAddress, indexingAddresses) {
|
|
234
|
+
let probe = dN => {
|
|
235
|
+
let tag = EventRouter.getSvmEventId(programId, dN);
|
|
236
|
+
return EventRouter.get(router, tag, contractAddress, instr.slot, indexingAddresses);
|
|
237
|
+
};
|
|
238
|
+
let result = Belt_Array.reduce(byteLengthsDesc, undefined, (acc, len) => {
|
|
239
|
+
if (acc !== undefined) {
|
|
240
|
+
return acc;
|
|
241
|
+
}
|
|
242
|
+
let candidate;
|
|
243
|
+
switch (len) {
|
|
244
|
+
case 1 :
|
|
245
|
+
candidate = instr.d1;
|
|
246
|
+
break;
|
|
247
|
+
case 2 :
|
|
248
|
+
candidate = instr.d2;
|
|
249
|
+
break;
|
|
250
|
+
case 4 :
|
|
251
|
+
candidate = instr.d4;
|
|
252
|
+
break;
|
|
253
|
+
case 8 :
|
|
254
|
+
candidate = instr.d8;
|
|
255
|
+
break;
|
|
256
|
+
default:
|
|
257
|
+
candidate = undefined;
|
|
258
|
+
}
|
|
259
|
+
if (candidate !== undefined) {
|
|
260
|
+
return probe(candidate);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
if (result !== undefined) {
|
|
264
|
+
return result;
|
|
265
|
+
} else {
|
|
266
|
+
return probe(undefined);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function make(param) {
|
|
271
|
+
let eventConfigs = param.eventConfigs;
|
|
272
|
+
let chain = param.chain;
|
|
273
|
+
let name = "HyperSyncSolana";
|
|
274
|
+
let client = HyperSyncSolanaClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, param.clientMaxRetries, undefined, undefined);
|
|
275
|
+
let match = EventRouter.fromSvmEventConfigsOrThrow(eventConfigs, chain);
|
|
276
|
+
let eventRouter = match[0];
|
|
277
|
+
let orderingByProgram = {};
|
|
278
|
+
Belt_Array.forEach(match[1], o => {
|
|
279
|
+
orderingByProgram[o.programId] = o.byteLengthsDesc;
|
|
280
|
+
});
|
|
281
|
+
let schemaHandlesByProgram = buildSchemaHandles(eventConfigs);
|
|
282
|
+
let getItemsOrThrow = async (fromBlock, toBlock, param, indexingAddresses, knownHeight, param$1, param$2, retry, logger) => {
|
|
283
|
+
let totalTimeRef = Hrtime.makeTimer();
|
|
284
|
+
let pageFetchRef = Hrtime.makeTimer();
|
|
285
|
+
let instructionSelections = buildInstructionSelections(eventConfigs);
|
|
286
|
+
let query_instructions = instructionSelections;
|
|
287
|
+
let query = {
|
|
288
|
+
fromSlot: fromBlock,
|
|
289
|
+
toSlot: toBlock,
|
|
290
|
+
instructions: query_instructions
|
|
291
|
+
};
|
|
292
|
+
Prometheus.SourceRequestCount.increment(name, chain, "getInstructions");
|
|
293
|
+
let resp;
|
|
294
|
+
try {
|
|
295
|
+
resp = await client.get(query);
|
|
296
|
+
} catch (raw_exn) {
|
|
297
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
298
|
+
throw {
|
|
299
|
+
RE_EXN_ID: Source.GetItemsError,
|
|
300
|
+
_1: {
|
|
301
|
+
TAG: "FailedGettingItems",
|
|
302
|
+
exn: exn,
|
|
303
|
+
attemptedToBlock: Stdlib_Option.getOr(toBlock, knownHeight),
|
|
304
|
+
retry: {
|
|
305
|
+
TAG: "WithBackoff",
|
|
306
|
+
message: `Unexpected issue while fetching instructions from HyperSync Solana. Attempt a retry.`,
|
|
307
|
+
backoffMillis: retry !== 0 ? 1000 * retry | 0 : 500
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
Error: new Error()
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
let pageFetchTime = Hrtime.toSecondsFloat(Hrtime.timeSince(pageFetchRef));
|
|
314
|
+
let parsingRef = Hrtime.makeTimer();
|
|
315
|
+
let txByKey = {};
|
|
316
|
+
Belt_Array.forEach(resp.data.transactions, tx => {
|
|
317
|
+
let key = tx.slot.toString() + ":" + tx.transactionIndex.toString();
|
|
318
|
+
txByKey[key] = tx;
|
|
319
|
+
});
|
|
320
|
+
let logsByKey = {};
|
|
321
|
+
Belt_Array.forEach(resp.data.logs, log => {
|
|
322
|
+
let match = log.transactionIndex;
|
|
323
|
+
let match$1 = log.instructionAddress;
|
|
324
|
+
if (match === undefined) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (match$1 === undefined) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
let key = log.slot.toString() + ":" + match.toString() + ":" + serializeInstructionAddress(match$1);
|
|
331
|
+
let existing = logsByKey[key];
|
|
332
|
+
if (existing !== undefined) {
|
|
333
|
+
existing.push(log);
|
|
334
|
+
} else {
|
|
335
|
+
logsByKey[key] = [log];
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
let parsedQueueItems = [];
|
|
339
|
+
Belt_Array.forEach(resp.data.instructions, instr => {
|
|
340
|
+
let programId = instr.programId;
|
|
341
|
+
let byteLengths = Stdlib_Option.getOr(orderingByProgram[instr.programId], []);
|
|
342
|
+
let contractAddress = instr.programId;
|
|
343
|
+
let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress, indexingAddresses);
|
|
344
|
+
if (maybeConfig !== undefined) {
|
|
345
|
+
let txKey = instr.slot.toString() + ":" + instr.transactionIndex.toString();
|
|
346
|
+
let maybeTx = Stdlib_Option.map(txByKey[txKey], toSvmTransaction);
|
|
347
|
+
let logKey = instr.slot.toString() + ":" + instr.transactionIndex.toString() + ":" + serializeInstructionAddress(instr.instructionAddress);
|
|
348
|
+
let maybeLogs = Stdlib_Option.map(logsByKey[logKey], logs => logs.map(log => ({
|
|
349
|
+
kind: Stdlib_Option.getOr(log.kind, ""),
|
|
350
|
+
message: Stdlib_Option.getOr(log.message, "")
|
|
351
|
+
})));
|
|
352
|
+
let payload_contractName = maybeConfig.contractName;
|
|
353
|
+
let payload_eventName = maybeConfig.name;
|
|
354
|
+
let payload_instruction = toSvmInstruction(instr, schemaHandlesByProgram);
|
|
355
|
+
let payload_transaction = maybeConfig.includeTransaction ? maybeTx : undefined;
|
|
356
|
+
let payload_logs = maybeConfig.includeLogs ? maybeLogs : undefined;
|
|
357
|
+
let payload_slot = instr.slot;
|
|
358
|
+
let payload_block = {
|
|
359
|
+
height: instr.slot,
|
|
360
|
+
time: 0,
|
|
361
|
+
hash: ""
|
|
362
|
+
};
|
|
363
|
+
let payload = {
|
|
364
|
+
contractName: payload_contractName,
|
|
365
|
+
eventName: payload_eventName,
|
|
366
|
+
instruction: payload_instruction,
|
|
367
|
+
transaction: payload_transaction,
|
|
368
|
+
logs: payload_logs,
|
|
369
|
+
slot: payload_slot,
|
|
370
|
+
blockTime: undefined,
|
|
371
|
+
block: payload_block
|
|
372
|
+
};
|
|
373
|
+
parsedQueueItems.push({
|
|
374
|
+
kind: 0,
|
|
375
|
+
eventConfig: maybeConfig,
|
|
376
|
+
timestamp: 0,
|
|
377
|
+
chain: chain,
|
|
378
|
+
blockNumber: instr.slot,
|
|
379
|
+
logIndex: synthLogIndex(instr),
|
|
380
|
+
event: payload
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
let parsingTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(parsingRef));
|
|
385
|
+
let heighestSlot = resp.nextSlot - 1 | 0;
|
|
386
|
+
let reorgGuard_rangeLastBlock = {
|
|
387
|
+
blockHash: "",
|
|
388
|
+
blockNumber: heighestSlot,
|
|
389
|
+
blockTimestamp: 0
|
|
390
|
+
};
|
|
391
|
+
let reorgGuard = {
|
|
392
|
+
rangeLastBlock: reorgGuard_rangeLastBlock,
|
|
393
|
+
prevRangeLastBlock: undefined
|
|
394
|
+
};
|
|
395
|
+
let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(totalTimeRef));
|
|
396
|
+
return {
|
|
397
|
+
knownHeight: knownHeight,
|
|
398
|
+
reorgGuard: reorgGuard,
|
|
399
|
+
parsedQueueItems: parsedQueueItems,
|
|
400
|
+
fromBlockQueried: fromBlock,
|
|
401
|
+
latestFetchedBlockNumber: heighestSlot,
|
|
402
|
+
latestFetchedBlockTimestamp: 0,
|
|
403
|
+
stats: {
|
|
404
|
+
"total time elapsed (s)": totalTimeElapsed,
|
|
405
|
+
"parsing time (s)": parsingTimeElapsed,
|
|
406
|
+
"page fetch time (s)": pageFetchTime
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
};
|
|
410
|
+
return {
|
|
411
|
+
name: name,
|
|
412
|
+
sourceFor: "Sync",
|
|
413
|
+
chain: chain,
|
|
414
|
+
poweredByHyperSync: true,
|
|
415
|
+
pollingInterval: 1000,
|
|
416
|
+
getBlockHashes: (param, param$1) => Stdlib_JsError.throwWithMessage("HyperSyncSolanaSource does not support getBlockHashes yet (reorg detection at finalized commitment is no-op in C2)"),
|
|
417
|
+
getHeightOrThrow: async () => {
|
|
418
|
+
let timer = Hrtime.makeTimer();
|
|
419
|
+
let h = await client.getHeight();
|
|
420
|
+
let seconds = Hrtime.toSecondsFloat(Hrtime.timeSince(timer));
|
|
421
|
+
Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
|
|
422
|
+
Prometheus.SourceRequestCount.addSeconds(name, chain, "getHeight", seconds);
|
|
423
|
+
return h;
|
|
424
|
+
},
|
|
425
|
+
getItemsOrThrow: getItemsOrThrow
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export {
|
|
430
|
+
EventRoutingFailed,
|
|
431
|
+
buildInstructionSelections,
|
|
432
|
+
synthLogIndex,
|
|
433
|
+
serializeInstructionAddress,
|
|
434
|
+
buildSchemaHandles,
|
|
435
|
+
decodeIfPossible,
|
|
436
|
+
toSvmInstruction,
|
|
437
|
+
toSvmTransaction,
|
|
438
|
+
probeRouter,
|
|
439
|
+
make,
|
|
440
|
+
}
|
|
441
|
+
/* Core Not a pure module */
|
|
@@ -192,18 +192,15 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`)
|
|
|
192
192
|
switch hscDecoder.contents {
|
|
193
193
|
| Some(decoder) => decoder
|
|
194
194
|
| None =>
|
|
195
|
-
switch HyperSyncClient.Decoder.fromSignatures(
|
|
195
|
+
switch HyperSyncClient.Decoder.fromSignatures(
|
|
196
|
+
allEventSignatures,
|
|
197
|
+
~checksumAddresses=!lowercaseAddresses,
|
|
198
|
+
) {
|
|
196
199
|
| exception exn =>
|
|
197
200
|
exn->ErrorHandling.mkLogAndRaise(
|
|
198
201
|
~msg="Failed to instantiate a decoder from hypersync client, please double check your ABI",
|
|
199
202
|
)
|
|
200
|
-
| decoder =>
|
|
201
|
-
if lowercaseAddresses {
|
|
202
|
-
decoder.disableChecksummedAddresses()
|
|
203
|
-
} else {
|
|
204
|
-
decoder.enableChecksummedAddresses()
|
|
205
|
-
}
|
|
206
|
-
decoder
|
|
203
|
+
| decoder => decoder
|
|
207
204
|
}
|
|
208
205
|
}
|
|
209
206
|
}
|
|
@@ -135,19 +135,12 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
|
|
|
135
135
|
if (decoder !== undefined) {
|
|
136
136
|
return decoder;
|
|
137
137
|
}
|
|
138
|
-
let decoder$1;
|
|
139
138
|
try {
|
|
140
|
-
|
|
139
|
+
return HyperSyncClient.Decoder.fromSignatures(allEventSignatures, !lowercaseAddresses);
|
|
141
140
|
} catch (raw_exn) {
|
|
142
141
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
143
142
|
return ErrorHandling.mkLogAndRaise(undefined, "Failed to instantiate a decoder from hypersync client, please double check your ABI", exn);
|
|
144
143
|
}
|
|
145
|
-
if (lowercaseAddresses) {
|
|
146
|
-
decoder$1.disableChecksummedAddresses();
|
|
147
|
-
} else {
|
|
148
|
-
decoder$1.enableChecksummedAddresses();
|
|
149
|
-
}
|
|
150
|
-
return decoder$1;
|
|
151
144
|
};
|
|
152
145
|
let UndefinedValue = /* @__PURE__ */Primitive_exceptions.create("UndefinedValue");
|
|
153
146
|
let makeEventBatchQueueItem = (item, params, eventConfig) => {
|
|
@@ -1022,7 +1022,7 @@ function make(param) {
|
|
|
1022
1022
|
if (decoder !== undefined) {
|
|
1023
1023
|
return decoder;
|
|
1024
1024
|
} else {
|
|
1025
|
-
return HyperSyncClient.Decoder.fromSignatures(allEventSignatures);
|
|
1025
|
+
return HyperSyncClient.Decoder.fromSignatures(allEventSignatures, undefined);
|
|
1026
1026
|
}
|
|
1027
1027
|
};
|
|
1028
1028
|
let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, indexingAddresses, knownHeight, partitionId, selection, param, param$1) => {
|
package/src/sources/Svm.res
CHANGED
|
@@ -39,7 +39,7 @@ module GetFinalizedSlot = {
|
|
|
39
39
|
)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
let makeRPCSource = (~chain, ~rpc: string): Source.t => {
|
|
42
|
+
let makeRPCSource = (~chain, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): Source.t => {
|
|
43
43
|
let client = Rest.client(rpc)
|
|
44
44
|
let chainId = chain->ChainMap.Chain.toChainId
|
|
45
45
|
|
|
@@ -54,7 +54,7 @@ let makeRPCSource = (~chain, ~rpc: string): Source.t => {
|
|
|
54
54
|
|
|
55
55
|
{
|
|
56
56
|
name,
|
|
57
|
-
sourceFor
|
|
57
|
+
sourceFor,
|
|
58
58
|
chain,
|
|
59
59
|
poweredByHyperSync: false,
|
|
60
60
|
pollingInterval: 10_000,
|
package/src/sources/Svm.res.mjs
CHANGED
|
@@ -60,14 +60,15 @@ let GetFinalizedSlot = {
|
|
|
60
60
|
route: route
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
function makeRPCSource(chain, rpc) {
|
|
63
|
+
function makeRPCSource(chain, rpc, sourceForOpt) {
|
|
64
|
+
let sourceFor = sourceForOpt !== undefined ? sourceForOpt : "Sync";
|
|
64
65
|
let client = Rest.client(rpc, undefined);
|
|
65
66
|
let host = Utils.Url.getHostFromUrl(rpc);
|
|
66
67
|
let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` + String(chain) + ` is in incorrect format. The RPC url needs to start with either http:// or https://`);
|
|
67
68
|
let name = `RPC (` + urlHost + `)`;
|
|
68
69
|
return {
|
|
69
70
|
name: name,
|
|
70
|
-
sourceFor:
|
|
71
|
+
sourceFor: sourceFor,
|
|
71
72
|
chain: chain,
|
|
72
73
|
poweredByHyperSync: false,
|
|
73
74
|
pollingInterval: 10000,
|
package/src/tui/Tui.res
CHANGED
|
@@ -13,6 +13,7 @@ module ChainLine = {
|
|
|
13
13
|
~endBlock,
|
|
14
14
|
~poweredByHyperSync,
|
|
15
15
|
~eventsProcessed,
|
|
16
|
+
~blockUnit: string,
|
|
16
17
|
) => {
|
|
17
18
|
let chainsWidth = Pervasives.min(stdoutColumns - 2, 60)
|
|
18
19
|
let headerWidth = maxChainIdLength + 10 // 10 for additional text
|
|
@@ -27,9 +28,10 @@ module ChainLine = {
|
|
|
27
28
|
let toBlockStr = toBlock->TuiData.formatLocaleString
|
|
28
29
|
let eventsStr = eventsProcessed->TuiData.formatFloatLocaleString
|
|
29
30
|
|
|
31
|
+
let endLabel = blockUnit === "Slots" ? " (End Slot)" : " (End Block)"
|
|
30
32
|
let blocksText =
|
|
31
|
-
|
|
32
|
-
(endBlock->Option.isSome ?
|
|
33
|
+
`${blockUnit}: ${progressBlockStr} / ${toBlockStr}` ++
|
|
34
|
+
(endBlock->Option.isSome ? endLabel : "") ++ ` `
|
|
33
35
|
let eventsText = `Events: ${eventsStr}`
|
|
34
36
|
|
|
35
37
|
let fitsSameLine = blocksText->String.length + eventsText->String.length <= chainsWidth
|
|
@@ -210,6 +212,10 @@ module App = {
|
|
|
210
212
|
poweredByHyperSync: (
|
|
211
213
|
cf.sourceManager->SourceManager.getActiveSource
|
|
212
214
|
).poweredByHyperSync,
|
|
215
|
+
blockUnit: switch state.ctx.config.ecosystem.name {
|
|
216
|
+
| Svm => "Slots"
|
|
217
|
+
| Evm | Fuel => "Blocks"
|
|
218
|
+
},
|
|
213
219
|
}: TuiData.chain
|
|
214
220
|
)
|
|
215
221
|
})
|
|
@@ -249,6 +255,7 @@ module App = {
|
|
|
249
255
|
stdoutColumns={stdoutColumns}
|
|
250
256
|
poweredByHyperSync={chainData.poweredByHyperSync}
|
|
251
257
|
eventsProcessed={chainData.eventsProcessed}
|
|
258
|
+
blockUnit={chainData.blockUnit}
|
|
252
259
|
/>
|
|
253
260
|
})
|
|
254
261
|
->React.array}
|
package/src/tui/Tui.res.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import * as JsxRuntime from "react/jsx-runtime";
|
|
|
19
19
|
import * as BufferedProgressBar from "./components/BufferedProgressBar.res.mjs";
|
|
20
20
|
|
|
21
21
|
function Tui$ChainLine(props) {
|
|
22
|
+
let blockUnit = props.blockUnit;
|
|
22
23
|
let poweredByHyperSync = props.poweredByHyperSync;
|
|
23
24
|
let endBlock = props.endBlock;
|
|
24
25
|
let startBlock = props.startBlock;
|
|
@@ -33,8 +34,9 @@ function Tui$ChainLine(props) {
|
|
|
33
34
|
let progressBlockStr = TuiData.formatLocaleString(progressBlock);
|
|
34
35
|
let toBlockStr = TuiData.formatLocaleString(toBlock);
|
|
35
36
|
let eventsStr = TuiData.formatFloatLocaleString(props.eventsProcessed);
|
|
36
|
-
let
|
|
37
|
-
|
|
37
|
+
let endLabel = blockUnit === "Slots" ? " (End Slot)" : " (End Block)";
|
|
38
|
+
let blocksText = blockUnit + `: ` + progressBlockStr + ` / ` + toBlockStr + (
|
|
39
|
+
Stdlib_Option.isSome(endBlock) ? endLabel : ""
|
|
38
40
|
) + ` `;
|
|
39
41
|
let eventsText = `Events: ` + eventsStr;
|
|
40
42
|
let fitsSameLine = (blocksText.length + eventsText.length | 0) <= chainsWidth;
|
|
@@ -242,6 +244,17 @@ function Tui$App(props) {
|
|
|
242
244
|
})
|
|
243
245
|
) : "SearchingForEvents";
|
|
244
246
|
}
|
|
247
|
+
let match$1 = state.ctx.config.ecosystem.name;
|
|
248
|
+
let tmp;
|
|
249
|
+
switch (match$1) {
|
|
250
|
+
case "evm" :
|
|
251
|
+
case "fuel" :
|
|
252
|
+
tmp = "Blocks";
|
|
253
|
+
break;
|
|
254
|
+
case "svm" :
|
|
255
|
+
tmp = "Slots";
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
245
258
|
return {
|
|
246
259
|
chainId: cf.chainConfig.id.toString(),
|
|
247
260
|
eventsProcessed: numEventsProcessed,
|
|
@@ -254,7 +267,8 @@ function Tui$App(props) {
|
|
|
254
267
|
poweredByHyperSync: SourceManager.getActiveSource(cf.sourceManager).poweredByHyperSync,
|
|
255
268
|
progress: progress,
|
|
256
269
|
latestFetchedBlockNumber: latestFetchedBlockNumber,
|
|
257
|
-
knownHeight: knownHeight
|
|
270
|
+
knownHeight: knownHeight,
|
|
271
|
+
blockUnit: tmp
|
|
258
272
|
};
|
|
259
273
|
});
|
|
260
274
|
let totalEventsProcessed = Stdlib_Array.reduce(chains, 0, (acc, chain) => acc + chain.eventsProcessed);
|
|
@@ -292,7 +306,8 @@ function Tui$App(props) {
|
|
|
292
306
|
startBlock: chainData.startBlock,
|
|
293
307
|
endBlock: chainData.endBlock,
|
|
294
308
|
poweredByHyperSync: chainData.poweredByHyperSync,
|
|
295
|
-
eventsProcessed: chainData.eventsProcessed
|
|
309
|
+
eventsProcessed: chainData.eventsProcessed,
|
|
310
|
+
blockUnit: chainData.blockUnit
|
|
296
311
|
}, i.toString())),
|
|
297
312
|
JsxRuntime.jsx(Tui$TotalEventsProcessed, {
|
|
298
313
|
totalEventsProcessed: totalEventsProcessed,
|
|
@@ -30,6 +30,9 @@ type chain = {
|
|
|
30
30
|
progress: progress,
|
|
31
31
|
latestFetchedBlockNumber: int,
|
|
32
32
|
knownHeight: int,
|
|
33
|
+
/** Localized unit noun for this chain's progress. `"Slots"` on SVM,
|
|
34
|
+
`"Blocks"` everywhere else. Drives the per-chain progress label. */
|
|
35
|
+
blockUnit: string,
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
let minOfOption: (int, option<int>) => int = (a: int, b: option<int>) => {
|