envio 3.3.0-alpha.2 → 3.3.0-alpha.3
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/index.d.ts +23 -21
- package/package.json +6 -6
- package/src/ChainFetching.res +25 -0
- package/src/ChainFetching.res.mjs +19 -0
- package/src/CrossChainState.res +15 -0
- package/src/CrossChainState.res.mjs +12 -0
- package/src/Ecosystem.res +0 -2
- package/src/EventConfigBuilder.res +42 -18
- package/src/EventConfigBuilder.res.mjs +21 -9
- package/src/EventProcessing.res +53 -37
- package/src/EventProcessing.res.mjs +41 -36
- package/src/FetchState.res +53 -43
- package/src/FetchState.res.mjs +71 -54
- package/src/HandlerLoader.res +10 -1
- package/src/HandlerLoader.res.mjs +15 -8
- package/src/Internal.res +3 -3
- package/src/Internal.res.mjs +1 -1
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/PgStorage.res +4 -4
- package/src/PgStorage.res.mjs +5 -5
- package/src/Prometheus.res +10 -10
- package/src/Prometheus.res.mjs +9 -9
- package/src/PruneStaleHistory.res +2 -2
- package/src/PruneStaleHistory.res.mjs +3 -3
- package/src/Rollback.res +2 -2
- package/src/Rollback.res.mjs +3 -3
- package/src/SimulateItems.res +77 -15
- package/src/SimulateItems.res.mjs +63 -20
- package/src/TestIndexer.res +48 -36
- package/src/TestIndexer.res.mjs +35 -28
- package/src/bindings/Performance.res +7 -0
- package/src/bindings/Performance.res.mjs +21 -0
- package/src/bindings/Performance.resi +7 -0
- package/src/sources/EventRouter.res +17 -21
- package/src/sources/EventRouter.res.mjs +6 -9
- package/src/sources/Evm.res +1 -35
- package/src/sources/Evm.res.mjs +2 -37
- package/src/sources/Fuel.res +0 -2
- package/src/sources/Fuel.res.mjs +0 -6
- package/src/sources/HyperFuelSource.res +10 -11
- package/src/sources/HyperFuelSource.res.mjs +11 -11
- package/src/sources/HyperSync.res +3 -0
- package/src/sources/HyperSync.res.mjs +1 -0
- package/src/sources/HyperSync.resi +1 -0
- package/src/sources/HyperSyncClient.res +5 -1
- package/src/sources/HyperSyncSource.res +42 -24
- package/src/sources/HyperSyncSource.res.mjs +30 -26
- package/src/sources/RpcSource.res +7 -8
- package/src/sources/RpcSource.res.mjs +8 -8
- package/src/sources/SimulateSource.res +1 -1
- package/src/sources/Source.res +1 -1
- package/src/sources/SourceManager.res +17 -16
- package/src/sources/SourceManager.res.mjs +10 -15
- package/src/sources/Svm.res +4 -10
- package/src/sources/Svm.res.mjs +5 -12
- package/src/sources/SvmHyperSyncSource.res +24 -18
- package/src/sources/SvmHyperSyncSource.res.mjs +22 -15
- package/src/sources/TransactionStore.res +59 -42
- package/src/sources/TransactionStore.res.mjs +21 -1
- package/svm.schema.json +30 -37
- package/src/bindings/Hrtime.res +0 -58
- package/src/bindings/Hrtime.res.mjs +0 -90
- package/src/bindings/Hrtime.resi +0 -30
package/src/sources/Svm.res
CHANGED
|
@@ -20,16 +20,10 @@ let transactionFields = [
|
|
|
20
20
|
"tokenBalances",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
let transactionFieldCodes = TransactionStore.fieldCodes(transactionFields)
|
|
25
|
-
|
|
26
|
-
let transactionFieldMask = (eventConfigs: array<Internal.eventConfig>): float =>
|
|
27
|
-
eventConfigs->TransactionStore.mask(~codes=transactionFieldCodes)
|
|
23
|
+
let transactionFieldMask = TransactionStore.makeMaskFn(transactionFields)
|
|
28
24
|
|
|
29
25
|
let make = (~logger: Pino.t): Ecosystem.t => {
|
|
30
26
|
name: Svm,
|
|
31
|
-
blockFields: ["slot"],
|
|
32
|
-
transactionFields,
|
|
33
27
|
blockNumberName: "height",
|
|
34
28
|
blockTimestampName: "time",
|
|
35
29
|
blockHashName: "hash",
|
|
@@ -94,9 +88,9 @@ let makeRPCSource = (~chain, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): S
|
|
|
94
88
|
getBlockHashes: (~blockNumbers as _, ~logger as _) =>
|
|
95
89
|
JsError.throwWithMessage("Svm does not support getting block hashes"),
|
|
96
90
|
getHeightOrThrow: async () => {
|
|
97
|
-
let timerRef =
|
|
91
|
+
let timerRef = Performance.now()
|
|
98
92
|
let height = await GetFinalizedSlot.route->Rest.fetch((), ~client)
|
|
99
|
-
let seconds = timerRef->
|
|
93
|
+
let seconds = timerRef->Performance.secondsSince
|
|
100
94
|
Prometheus.SourceRequestCount.increment(~sourceName=name, ~chainId, ~method="getSlot")
|
|
101
95
|
Prometheus.SourceRequestCount.addSeconds(
|
|
102
96
|
~sourceName=name,
|
|
@@ -110,7 +104,7 @@ let makeRPCSource = (~chain, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): S
|
|
|
110
104
|
~fromBlock as _,
|
|
111
105
|
~toBlock as _,
|
|
112
106
|
~addressesByContractName as _,
|
|
113
|
-
~
|
|
107
|
+
~contractNameByAddress as _,
|
|
114
108
|
~knownHeight as _,
|
|
115
109
|
~partitionId as _,
|
|
116
110
|
~selection as _,
|
package/src/sources/Svm.res.mjs
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import * as Rpc from "./Rpc.res.mjs";
|
|
4
4
|
import * as Rest from "../vendored/Rest.res.mjs";
|
|
5
5
|
import * as Utils from "../Utils.res.mjs";
|
|
6
|
-
import * as Hrtime from "../bindings/Hrtime.res.mjs";
|
|
7
6
|
import * as Logging from "../Logging.res.mjs";
|
|
8
7
|
import * as Prometheus from "../Prometheus.res.mjs";
|
|
8
|
+
import * as Performance from "../bindings/Performance.res.mjs";
|
|
9
9
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
10
10
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
11
11
|
import * as TransactionStore from "./TransactionStore.res.mjs";
|
|
@@ -30,17 +30,11 @@ let transactionFields = [
|
|
|
30
30
|
"tokenBalances"
|
|
31
31
|
];
|
|
32
32
|
|
|
33
|
-
let
|
|
34
|
-
|
|
35
|
-
function transactionFieldMask(eventConfigs) {
|
|
36
|
-
return TransactionStore.mask(eventConfigs, transactionFieldCodes);
|
|
37
|
-
}
|
|
33
|
+
let transactionFieldMask = TransactionStore.makeMaskFn(transactionFields);
|
|
38
34
|
|
|
39
35
|
function make(logger) {
|
|
40
36
|
return {
|
|
41
37
|
name: "svm",
|
|
42
|
-
blockFields: ["slot"],
|
|
43
|
-
transactionFields: transactionFields,
|
|
44
38
|
blockNumberName: "height",
|
|
45
39
|
blockTimestampName: "time",
|
|
46
40
|
blockHashName: "hash",
|
|
@@ -89,9 +83,9 @@ function makeRPCSource(chain, rpc, sourceForOpt) {
|
|
|
89
83
|
pollingInterval: 10000,
|
|
90
84
|
getBlockHashes: (param, param$1) => Stdlib_JsError.throwWithMessage("Svm does not support getting block hashes"),
|
|
91
85
|
getHeightOrThrow: async () => {
|
|
92
|
-
let timerRef =
|
|
86
|
+
let timerRef = Performance.now();
|
|
93
87
|
let height = await Rest.fetch(route, undefined, client);
|
|
94
|
-
let seconds =
|
|
88
|
+
let seconds = Performance.secondsSince(timerRef);
|
|
95
89
|
Prometheus.SourceRequestCount.increment(name, chain, "getSlot");
|
|
96
90
|
Prometheus.SourceRequestCount.addSeconds(name, chain, "getSlot", seconds);
|
|
97
91
|
return height;
|
|
@@ -103,10 +97,9 @@ function makeRPCSource(chain, rpc, sourceForOpt) {
|
|
|
103
97
|
export {
|
|
104
98
|
cleanUpRawEventFieldsInPlace,
|
|
105
99
|
transactionFields,
|
|
106
|
-
transactionFieldCodes,
|
|
107
100
|
transactionFieldMask,
|
|
108
101
|
make,
|
|
109
102
|
GetFinalizedSlot,
|
|
110
103
|
makeRPCSource,
|
|
111
104
|
}
|
|
112
|
-
/*
|
|
105
|
+
/* transactionFieldMask Not a pure module */
|
|
@@ -216,11 +216,11 @@ let probeRouter = (
|
|
|
216
216
|
instr: SvmHyperSyncClient.ResponseTypes.instruction,
|
|
217
217
|
byteLengthsDesc: array<int>,
|
|
218
218
|
~contractAddress,
|
|
219
|
-
~
|
|
219
|
+
~contractNameByAddress,
|
|
220
220
|
) => {
|
|
221
221
|
let probe = (dN: option<string>) => {
|
|
222
222
|
let tag = EventRouter.getSvmEventId(~programId, ~discriminator=dN)
|
|
223
|
-
router->EventRouter.get(~tag, ~contractAddress, ~
|
|
223
|
+
router->EventRouter.get(~tag, ~contractAddress, ~contractNameByAddress)
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
let result = byteLengthsDesc->Array.reduce(None, (acc, len) =>
|
|
@@ -319,26 +319,32 @@ let make = ({chain, endpointUrl, apiToken, eventConfigs, clientTimeoutMillis}: o
|
|
|
319
319
|
)
|
|
320
320
|
fields
|
|
321
321
|
}
|
|
322
|
-
//
|
|
323
|
-
// stored transaction record
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
322
|
+
// The transaction table is fetched only when a selected field is actually read
|
|
323
|
+
// off a stored transaction record. `transactionIndex` materialises from the
|
|
324
|
+
// store key and `tokenBalances` lives in its own table, so neither requires it.
|
|
325
|
+
let needsTransactions =
|
|
326
|
+
selectedTxFields
|
|
327
|
+
->Utils.Set.toArray
|
|
328
|
+
->Array.some(field =>
|
|
329
|
+
switch field {
|
|
330
|
+
| Internal.TransactionIndex | Internal.TokenBalances => false
|
|
331
|
+
| _ => true
|
|
332
|
+
}
|
|
333
|
+
)
|
|
328
334
|
|
|
329
335
|
let getItemsOrThrow = async (
|
|
330
336
|
~fromBlock,
|
|
331
337
|
~toBlock,
|
|
332
338
|
~addressesByContractName as _,
|
|
333
|
-
~
|
|
339
|
+
~contractNameByAddress,
|
|
334
340
|
~knownHeight,
|
|
335
341
|
~partitionId as _,
|
|
336
342
|
~selection as _,
|
|
337
343
|
~retry,
|
|
338
344
|
~logger,
|
|
339
345
|
) => {
|
|
340
|
-
let totalTimeRef =
|
|
341
|
-
let pageFetchRef =
|
|
346
|
+
let totalTimeRef = Performance.now()
|
|
347
|
+
let pageFetchRef = Performance.now()
|
|
342
348
|
|
|
343
349
|
let instructionSelections = buildInstructionSelections(eventConfigs)
|
|
344
350
|
// Under the server's default merge mode, requesting a table's columns is
|
|
@@ -384,9 +390,9 @@ let make = ({chain, endpointUrl, apiToken, eventConfigs, clientTimeoutMillis}: o
|
|
|
384
390
|
),
|
|
385
391
|
)
|
|
386
392
|
}
|
|
387
|
-
let pageFetchTime = pageFetchRef->
|
|
393
|
+
let pageFetchTime = pageFetchRef->Performance.secondsSince
|
|
388
394
|
|
|
389
|
-
let parsingRef =
|
|
395
|
+
let parsingRef = Performance.now()
|
|
390
396
|
|
|
391
397
|
// Per-slot unix timestamp lookup from the response's `blocks` table. Slots
|
|
392
398
|
// without a block row (rare; usually skipped slots) fall back to `None`.
|
|
@@ -434,7 +440,7 @@ let make = ({chain, endpointUrl, apiToken, eventConfigs, clientTimeoutMillis}: o
|
|
|
434
440
|
instr,
|
|
435
441
|
byteLengths,
|
|
436
442
|
~contractAddress,
|
|
437
|
-
~
|
|
443
|
+
~contractNameByAddress,
|
|
438
444
|
)
|
|
439
445
|
|
|
440
446
|
switch maybeConfig {
|
|
@@ -492,7 +498,7 @@ let make = ({chain, endpointUrl, apiToken, eventConfigs, clientTimeoutMillis}: o
|
|
|
492
498
|
let _ = logger
|
|
493
499
|
})
|
|
494
500
|
|
|
495
|
-
let parsingTimeElapsed = parsingRef->
|
|
501
|
+
let parsingTimeElapsed = parsingRef->Performance.secondsSince
|
|
496
502
|
let highestSlot = resp.nextSlot - 1
|
|
497
503
|
let latestBlockTime =
|
|
498
504
|
blockTimeBySlot
|
|
@@ -507,7 +513,7 @@ let make = ({chain, endpointUrl, apiToken, eventConfigs, clientTimeoutMillis}: o
|
|
|
507
513
|
blockHash: b.blockhash,
|
|
508
514
|
})
|
|
509
515
|
|
|
510
|
-
let totalTimeElapsed = totalTimeRef->
|
|
516
|
+
let totalTimeElapsed = totalTimeRef->Performance.secondsSince
|
|
511
517
|
|
|
512
518
|
{
|
|
513
519
|
latestFetchedBlockTimestamp: latestBlockTime,
|
|
@@ -597,9 +603,9 @@ let make = ({chain, endpointUrl, apiToken, eventConfigs, clientTimeoutMillis}: o
|
|
|
597
603
|
poweredByHyperSync: true,
|
|
598
604
|
getBlockHashes,
|
|
599
605
|
getHeightOrThrow: async () => {
|
|
600
|
-
let timer =
|
|
606
|
+
let timer = Performance.now()
|
|
601
607
|
let h = await client.getHeight()
|
|
602
|
-
let seconds = timer->
|
|
608
|
+
let seconds = timer->Performance.secondsSince
|
|
603
609
|
Prometheus.SourceRequestCount.increment(~sourceName=name, ~chainId, ~method="getHeight")
|
|
604
610
|
Prometheus.SourceRequestCount.addSeconds(
|
|
605
611
|
~sourceName=name,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as Hrtime from "../bindings/Hrtime.res.mjs";
|
|
4
3
|
import * as Source from "./Source.res.mjs";
|
|
5
4
|
import * as Prometheus from "../Prometheus.res.mjs";
|
|
6
5
|
import * as EventRouter from "./EventRouter.res.mjs";
|
|
6
|
+
import * as Performance from "../bindings/Performance.res.mjs";
|
|
7
7
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
8
8
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
9
9
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
@@ -185,10 +185,10 @@ function toSvmInstruction(instr, programName, instructionName, logs, block) {
|
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
function probeRouter(router, programId, instr, byteLengthsDesc, contractAddress,
|
|
188
|
+
function probeRouter(router, programId, instr, byteLengthsDesc, contractAddress, contractNameByAddress) {
|
|
189
189
|
let probe = dN => {
|
|
190
190
|
let tag = EventRouter.getSvmEventId(programId, dN);
|
|
191
|
-
return EventRouter.get(router, tag, contractAddress,
|
|
191
|
+
return EventRouter.get(router, tag, contractAddress, contractNameByAddress);
|
|
192
192
|
};
|
|
193
193
|
let result = Stdlib_Array.reduce(byteLengthsDesc, undefined, (acc, len) => {
|
|
194
194
|
if (acc !== undefined) {
|
|
@@ -279,11 +279,18 @@ function make(param) {
|
|
|
279
279
|
return;
|
|
280
280
|
}
|
|
281
281
|
});
|
|
282
|
-
let
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
282
|
+
let needsTransactions = Array.from(selectedTxFields).some(field => {
|
|
283
|
+
switch (field) {
|
|
284
|
+
case "transactionIndex" :
|
|
285
|
+
case "tokenBalances" :
|
|
286
|
+
return false;
|
|
287
|
+
default:
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
let getItemsOrThrow = async (fromBlock, toBlock, param, contractNameByAddress, knownHeight, param$1, param$2, retry, logger) => {
|
|
292
|
+
let totalTimeRef = Performance.now();
|
|
293
|
+
let pageFetchRef = Performance.now();
|
|
287
294
|
let instructionSelections = buildInstructionSelections(eventConfigs);
|
|
288
295
|
let fields_block = [
|
|
289
296
|
"slot",
|
|
@@ -344,8 +351,8 @@ function make(param) {
|
|
|
344
351
|
};
|
|
345
352
|
}
|
|
346
353
|
let resp = match[0];
|
|
347
|
-
let pageFetchTime =
|
|
348
|
-
let parsingRef =
|
|
354
|
+
let pageFetchTime = Performance.secondsSince(pageFetchRef);
|
|
355
|
+
let parsingRef = Performance.now();
|
|
349
356
|
let blockTimeBySlot = {};
|
|
350
357
|
resp.data.blocks.forEach(b => {
|
|
351
358
|
let t = b.blockTime;
|
|
@@ -377,7 +384,7 @@ function make(param) {
|
|
|
377
384
|
let programId = instr.programId;
|
|
378
385
|
let byteLengths = Stdlib_Option.getOr(orderingByProgram[instr.programId], []);
|
|
379
386
|
let contractAddress = instr.programId;
|
|
380
|
-
let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress,
|
|
387
|
+
let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress, contractNameByAddress);
|
|
381
388
|
if (maybeConfig !== undefined) {
|
|
382
389
|
let logKey = instr.slot.toString() + ":" + instr.transactionIndex.toString() + ":" + serializeInstructionAddress(instr.instructionAddress);
|
|
383
390
|
let maybeLogs = Stdlib_Option.map(logsByKey[logKey], logs => logs.map(log => ({
|
|
@@ -404,14 +411,14 @@ function make(param) {
|
|
|
404
411
|
});
|
|
405
412
|
}
|
|
406
413
|
});
|
|
407
|
-
let parsingTimeElapsed =
|
|
414
|
+
let parsingTimeElapsed = Performance.secondsSince(parsingRef);
|
|
408
415
|
let highestSlot = resp.nextSlot - 1 | 0;
|
|
409
416
|
let latestBlockTime = Stdlib_Option.getOr(blockTimeBySlot[highestSlot.toString()], 0);
|
|
410
417
|
let blockHashes = resp.data.blocks.map(b => ({
|
|
411
418
|
blockHash: b.blockhash,
|
|
412
419
|
blockNumber: b.slot
|
|
413
420
|
}));
|
|
414
|
-
let totalTimeElapsed =
|
|
421
|
+
let totalTimeElapsed = Performance.secondsSince(totalTimeRef);
|
|
415
422
|
return {
|
|
416
423
|
knownHeight: knownHeight,
|
|
417
424
|
blockHashes: blockHashes,
|
|
@@ -513,9 +520,9 @@ function make(param) {
|
|
|
513
520
|
pollingInterval: 1000,
|
|
514
521
|
getBlockHashes: getBlockHashes,
|
|
515
522
|
getHeightOrThrow: async () => {
|
|
516
|
-
let timer =
|
|
523
|
+
let timer = Performance.now();
|
|
517
524
|
let h = await client.getHeight();
|
|
518
|
-
let seconds =
|
|
525
|
+
let seconds = Performance.secondsSince(timer);
|
|
519
526
|
Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
|
|
520
527
|
Prometheus.SourceRequestCount.addSeconds(name, chain, "getHeight", seconds);
|
|
521
528
|
return h;
|
|
@@ -34,6 +34,13 @@ let mask = (eventConfigs: array<Internal.eventConfig>, ~codes: dict<int>): float
|
|
|
34
34
|
selected->Utils.Set.toArray->Array.reduce(0., (mask, code) => mask +. pow2(code))
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// Build an ecosystem's mask function from its ordered field-name array. The
|
|
38
|
+
// field codes are derived once and closed over.
|
|
39
|
+
let makeMaskFn = (fields: array<string>): (array<Internal.eventConfig> => float) => {
|
|
40
|
+
let codes = fieldCodes(fields)
|
|
41
|
+
eventConfigs => eventConfigs->mask(~codes)
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
// Drain another store (a fetch-response page) into this one.
|
|
38
45
|
@send external merge: (t, t) => unit = "merge"
|
|
39
46
|
|
|
@@ -60,52 +67,62 @@ external materialize: (
|
|
|
60
67
|
// selected none — so `event.transaction` is never `undefined` (matching the
|
|
61
68
|
// inline sources). Deduped per (blockNumber, transactionIndex).
|
|
62
69
|
let materializeItems = async (store: t, ~items: array<Internal.item>, ~mask: float) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
if mask == 0. {
|
|
71
|
+
// No fields selected: there's nothing to decode and no reason to group by
|
|
72
|
+
// key, but each store-backed item still gets an empty transaction object so
|
|
73
|
+
// `event.transaction` is never undefined (matching the inline sources).
|
|
74
|
+
items->Array.forEach(item =>
|
|
75
|
+
switch item {
|
|
76
|
+
| Internal.Event(_) =>
|
|
77
|
+
let payload = (item->Internal.castUnsafeEventItem).payload
|
|
78
|
+
switch payload->Internal.getPayloadTransaction->Nullable.toOption {
|
|
79
|
+
| Some(_) => () // RPC/simulate/Fuel carry the transaction inline.
|
|
80
|
+
| None => payload->Internal.setPayloadTransaction(%raw(`{}`))
|
|
81
|
+
}
|
|
82
|
+
| Internal.Block(_) => ()
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
} else {
|
|
86
|
+
// Store-backed items arrive in (block, logIndex) order, and a transaction's
|
|
87
|
+
// logs are contiguous within a block, so events sharing a (blockNumber,
|
|
88
|
+
// transactionIndex) are adjacent. Group them by extending the current run
|
|
89
|
+
// rather than hashing a string key per item. A key recurring non-adjacently
|
|
90
|
+
// just splits into two groups (one redundant decode) — never incorrect.
|
|
91
|
+
let blockNumbers = []
|
|
92
|
+
let transactionIndices = []
|
|
93
|
+
let payloadGroups = []
|
|
71
94
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
items->Array.forEach(item =>
|
|
96
|
+
switch item {
|
|
97
|
+
| Internal.Event(_) =>
|
|
98
|
+
let eventItem = item->Internal.castUnsafeEventItem
|
|
99
|
+
switch eventItem.payload->Internal.getPayloadTransaction->Nullable.toOption {
|
|
100
|
+
| Some(_) => () // RPC/simulate/Fuel carry the transaction inline.
|
|
101
|
+
| None =>
|
|
102
|
+
let {blockNumber, transactionIndex} = eventItem
|
|
103
|
+
let last = payloadGroups->Array.length - 1
|
|
104
|
+
if (
|
|
105
|
+
last >= 0 &&
|
|
106
|
+
blockNumbers->Array.getUnsafe(last) == blockNumber &&
|
|
107
|
+
transactionIndices->Array.getUnsafe(last) == transactionIndex
|
|
108
|
+
) {
|
|
109
|
+
payloadGroups->Array.getUnsafe(last)->Array.push(eventItem.payload)
|
|
110
|
+
} else {
|
|
111
|
+
blockNumbers->Array.push(blockNumber)
|
|
112
|
+
transactionIndices->Array.push(transactionIndex)
|
|
113
|
+
payloadGroups->Array.push([eventItem.payload])
|
|
114
|
+
}
|
|
91
115
|
}
|
|
116
|
+
| Internal.Block(_) => ()
|
|
92
117
|
}
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
)
|
|
118
|
+
)
|
|
96
119
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
} else {
|
|
104
|
-
await store->materialize(~blockNumbers, ~transactionIndices, ~mask)
|
|
120
|
+
if payloadGroups->Utils.Array.notEmpty {
|
|
121
|
+
let txs = await store->materialize(~blockNumbers, ~transactionIndices, ~mask)
|
|
122
|
+
payloadGroups->Array.forEachWithIndex((payloads, i) => {
|
|
123
|
+
let tx = txs->Array.getUnsafe(i)
|
|
124
|
+
payloads->Array.forEach(payload => payload->Internal.setPayloadTransaction(tx))
|
|
125
|
+
})
|
|
105
126
|
}
|
|
106
|
-
payloadGroups->Array.forEachWithIndex((payloads, i) => {
|
|
107
|
-
let tx = txs->Array.getUnsafe(i)
|
|
108
|
-
payloads->Array.forEach(payload => payload->Internal.setPayloadTransaction(tx))
|
|
109
|
-
})
|
|
110
127
|
}
|
|
111
128
|
}
|
|
@@ -32,7 +32,26 @@ function mask(eventConfigs, codes) {
|
|
|
32
32
|
return Stdlib_Array.reduce(Array.from(selected), 0, (mask, code) => mask + pow2(code));
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function makeMaskFn(fields) {
|
|
36
|
+
let codes = fieldCodes(fields);
|
|
37
|
+
return eventConfigs => mask(eventConfigs, codes);
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
async function materializeItems(store, items, mask) {
|
|
41
|
+
if (mask === 0) {
|
|
42
|
+
items.forEach(item => {
|
|
43
|
+
if (item.kind !== 0) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
let payload = item.payload;
|
|
47
|
+
let match = payload.transaction;
|
|
48
|
+
if (match == null) {
|
|
49
|
+
payload.transaction = {};
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
36
55
|
let blockNumbers = [];
|
|
37
56
|
let transactionIndices = [];
|
|
38
57
|
let payloadGroups = [];
|
|
@@ -58,7 +77,7 @@ async function materializeItems(store, items, mask) {
|
|
|
58
77
|
if (!Utils.$$Array.notEmpty(payloadGroups)) {
|
|
59
78
|
return;
|
|
60
79
|
}
|
|
61
|
-
let txs =
|
|
80
|
+
let txs = await store.materialize(blockNumbers, transactionIndices, mask);
|
|
62
81
|
payloadGroups.forEach((payloads, i) => {
|
|
63
82
|
let tx = txs[i];
|
|
64
83
|
payloads.forEach(payload => {
|
|
@@ -72,6 +91,7 @@ export {
|
|
|
72
91
|
fieldCodes,
|
|
73
92
|
pow2,
|
|
74
93
|
mask,
|
|
94
|
+
makeMaskFn,
|
|
75
95
|
materializeItems,
|
|
76
96
|
}
|
|
77
97
|
/* Core Not a pure module */
|
package/svm.schema.json
CHANGED
|
@@ -463,53 +463,46 @@
|
|
|
463
463
|
"type": "object",
|
|
464
464
|
"properties": {
|
|
465
465
|
"transaction_fields": {
|
|
466
|
-
"description": "
|
|
467
|
-
"
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
]
|
|
466
|
+
"description": "Parent-transaction fields to include on each matched instruction, as a list of field names. Omit (or pass an empty list) to include no transaction.",
|
|
467
|
+
"type": [
|
|
468
|
+
"array",
|
|
469
|
+
"null"
|
|
470
|
+
],
|
|
471
|
+
"items": {
|
|
472
|
+
"$ref": "#/$defs/SvmTransactionField"
|
|
473
|
+
}
|
|
475
474
|
},
|
|
476
475
|
"log_fields": {
|
|
477
|
-
"description": "
|
|
478
|
-
"
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
},
|
|
482
|
-
{
|
|
483
|
-
"type": "null"
|
|
484
|
-
}
|
|
476
|
+
"description": "Set to `true` to include program logs scoped to each matched instruction.",
|
|
477
|
+
"type": [
|
|
478
|
+
"boolean",
|
|
479
|
+
"null"
|
|
485
480
|
]
|
|
486
481
|
},
|
|
487
482
|
"token_balance_fields": {
|
|
488
|
-
"description": "
|
|
489
|
-
"
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
"type": "null"
|
|
495
|
-
}
|
|
483
|
+
"description": "Set to `true` to include SPL Token / Token-2022 balance snapshots for the parent transaction, exposed as `transaction.tokenBalances`. Independent of `transaction_fields`.",
|
|
484
|
+
"type": [
|
|
485
|
+
"boolean",
|
|
486
|
+
"null"
|
|
496
487
|
]
|
|
497
488
|
}
|
|
498
489
|
},
|
|
499
490
|
"additionalProperties": false
|
|
500
491
|
},
|
|
501
|
-
"
|
|
502
|
-
"description": "
|
|
503
|
-
"
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
492
|
+
"SvmTransactionField": {
|
|
493
|
+
"description": "Selectable parent-transaction field names (camelCase), matching the\npublic `svmTransaction` shape. `tokenBalances` is selected via the\nseparate `token_balance_fields` toggle, so it isn't listed here.",
|
|
494
|
+
"type": "string",
|
|
495
|
+
"enum": [
|
|
496
|
+
"transactionIndex",
|
|
497
|
+
"signatures",
|
|
498
|
+
"feePayer",
|
|
499
|
+
"success",
|
|
500
|
+
"err",
|
|
501
|
+
"fee",
|
|
502
|
+
"computeUnitsConsumed",
|
|
503
|
+
"accountKeys",
|
|
504
|
+
"recentBlockhash",
|
|
505
|
+
"version"
|
|
513
506
|
]
|
|
514
507
|
},
|
|
515
508
|
"ArgDef": {
|
package/src/bindings/Hrtime.res
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
type seconds = float
|
|
2
|
-
type milliseconds = float
|
|
3
|
-
type nanoseconds = float
|
|
4
|
-
|
|
5
|
-
type timeTuple = (seconds, nanoseconds)
|
|
6
|
-
|
|
7
|
-
type timeRef = timeTuple
|
|
8
|
-
|
|
9
|
-
type timeElapsed = timeTuple
|
|
10
|
-
|
|
11
|
-
@val @scope("process") external makeTimer: unit => timeRef = "hrtime"
|
|
12
|
-
|
|
13
|
-
@val @scope("process") external timeSince: timeRef => timeElapsed = "hrtime"
|
|
14
|
-
|
|
15
|
-
let nanoToMilli = (nano: nanoseconds): milliseconds => nano /. 1_000_000.
|
|
16
|
-
let secToMilli = (sec: seconds): milliseconds => sec *. 1_000.
|
|
17
|
-
|
|
18
|
-
let nanoToTimeTuple = (nano: nanoseconds): timeTuple => {
|
|
19
|
-
let factor = 1_000_000_000.
|
|
20
|
-
let seconds = Math.floor(nano /. factor)
|
|
21
|
-
let nanos = Float.mod(nano, factor)
|
|
22
|
-
(seconds, nanos)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
let timeElapsedToNewRef = (elapsed: timeElapsed, ref: timeRef): timeRef => {
|
|
26
|
-
let (elapsedSeconds, elapsedNano) = elapsed
|
|
27
|
-
let (refSeconds, refNano) = ref
|
|
28
|
-
|
|
29
|
-
let (nanoExtraSeconds, remainderNanos) = nanoToTimeTuple(elapsedNano +. refNano)
|
|
30
|
-
(elapsedSeconds +. refSeconds +. nanoExtraSeconds, remainderNanos)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
let toMillis = ((sec, nano): timeElapsed): milliseconds => {
|
|
34
|
-
sec->secToMilli +. nano->nanoToMilli
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let toSeconds = ((sec, nano): timeElapsed): seconds => {
|
|
38
|
-
sec +. nano /. 1_000_000_000.
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let toSecondsFloat = (elapsed: timeElapsed): float => {
|
|
42
|
-
elapsed->toSeconds->(Utils.magic: seconds => float)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let toInt = float => float->Int.fromFloat
|
|
46
|
-
let intFromMillis = toInt
|
|
47
|
-
let intFromNanos = toInt
|
|
48
|
-
let intFromSeconds = toInt
|
|
49
|
-
let floatFromMillis: milliseconds => float = v => v->(Utils.magic: milliseconds => float)
|
|
50
|
-
let floatFromSeconds: seconds => float = v => v->(Utils.magic: seconds => float)
|
|
51
|
-
|
|
52
|
-
let millisBetween = (~from: timeRef, ~to: timeRef): int => {
|
|
53
|
-
to->toMillis->intFromMillis - from->toMillis->intFromMillis
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let secondsBetween = (~from: timeRef, ~to: timeRef): float => {
|
|
57
|
-
to->toSecondsFloat -. from->toSecondsFloat
|
|
58
|
-
}
|