envio 3.3.0-alpha.7 → 3.3.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/index.d.ts +23 -5
  2. package/package.json +6 -6
  3. package/src/Api.res +1 -1
  4. package/src/Api.res.mjs +1 -1
  5. package/src/ChainFetching.res +21 -10
  6. package/src/ChainFetching.res.mjs +11 -10
  7. package/src/ChainState.res +401 -171
  8. package/src/ChainState.res.mjs +270 -104
  9. package/src/ChainState.resi +19 -7
  10. package/src/Config.res +11 -27
  11. package/src/Config.res.mjs +8 -7
  12. package/src/Core.res +7 -0
  13. package/src/CrossChainState.res +82 -82
  14. package/src/CrossChainState.res.mjs +52 -59
  15. package/src/CrossChainState.resi +1 -1
  16. package/src/Ecosystem.res +3 -3
  17. package/src/Ecosystem.res.mjs +3 -3
  18. package/src/Envio.res +14 -9
  19. package/src/EnvioGlobal.res +53 -0
  20. package/src/EnvioGlobal.res.mjs +31 -0
  21. package/src/EventConfigBuilder.res +117 -69
  22. package/src/EventConfigBuilder.res.mjs +71 -34
  23. package/src/EventProcessing.res +19 -15
  24. package/src/EventProcessing.res.mjs +13 -12
  25. package/src/FetchState.res +410 -185
  26. package/src/FetchState.res.mjs +268 -253
  27. package/src/HandlerLoader.res +8 -113
  28. package/src/HandlerLoader.res.mjs +2 -88
  29. package/src/HandlerRegister.res +518 -144
  30. package/src/HandlerRegister.res.mjs +285 -133
  31. package/src/HandlerRegister.resi +24 -8
  32. package/src/IndexerState.res +6 -3
  33. package/src/IndexerState.res.mjs +3 -3
  34. package/src/IndexerState.resi +1 -1
  35. package/src/IndexingAddresses.res +10 -7
  36. package/src/IndexingAddresses.res.mjs +8 -7
  37. package/src/IndexingAddresses.resi +3 -1
  38. package/src/Internal.res +104 -39
  39. package/src/Internal.res.mjs +11 -1
  40. package/src/LogSelection.res +102 -165
  41. package/src/LogSelection.res.mjs +101 -116
  42. package/src/Main.res +49 -164
  43. package/src/Main.res.mjs +39 -104
  44. package/src/Metrics.res +43 -2
  45. package/src/Metrics.res.mjs +39 -3
  46. package/src/Prometheus.res +0 -35
  47. package/src/Prometheus.res.mjs +33 -68
  48. package/src/RawEvent.res +7 -2
  49. package/src/RawEvent.res.mjs +4 -4
  50. package/src/RollbackCommit.res +4 -1
  51. package/src/RollbackCommit.res.mjs +3 -2
  52. package/src/SimulateItems.res +20 -7
  53. package/src/SimulateItems.res.mjs +7 -11
  54. package/src/TestIndexer.res +1 -1
  55. package/src/TestIndexer.res.mjs +1 -1
  56. package/src/sources/BlockStore.res +46 -0
  57. package/src/sources/BlockStore.res.mjs +24 -0
  58. package/src/sources/EventRouter.res +19 -12
  59. package/src/sources/EventRouter.res.mjs +7 -5
  60. package/src/sources/Evm.res +58 -5
  61. package/src/sources/Evm.res.mjs +44 -5
  62. package/src/sources/EvmChain.res +14 -18
  63. package/src/sources/EvmChain.res.mjs +12 -13
  64. package/src/sources/FieldMask.res +39 -0
  65. package/src/sources/FieldMask.res.mjs +42 -0
  66. package/src/sources/Fuel.res +8 -3
  67. package/src/sources/Fuel.res.mjs +5 -4
  68. package/src/sources/HyperFuelSource.res +31 -40
  69. package/src/sources/HyperFuelSource.res.mjs +52 -44
  70. package/src/sources/HyperSync.res +31 -9
  71. package/src/sources/HyperSync.res.mjs +47 -31
  72. package/src/sources/HyperSync.resi +10 -3
  73. package/src/sources/HyperSyncClient.res +15 -4
  74. package/src/sources/HyperSyncHeightStream.res +1 -8
  75. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  76. package/src/sources/HyperSyncSource.res +58 -90
  77. package/src/sources/HyperSyncSource.res.mjs +57 -66
  78. package/src/sources/RpcSource.res +118 -120
  79. package/src/sources/RpcSource.res.mjs +92 -74
  80. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  81. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  82. package/src/sources/SimulateSource.res +5 -3
  83. package/src/sources/SimulateSource.res.mjs +12 -4
  84. package/src/sources/Source.res +19 -5
  85. package/src/sources/SourceManager.res +60 -10
  86. package/src/sources/SourceManager.res.mjs +54 -8
  87. package/src/sources/SourceManager.resi +10 -0
  88. package/src/sources/Svm.res +14 -10
  89. package/src/sources/Svm.res.mjs +23 -6
  90. package/src/sources/SvmHyperSyncClient.res +5 -6
  91. package/src/sources/SvmHyperSyncSource.res +82 -41
  92. package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
  93. package/src/sources/TransactionStore.res +6 -107
  94. package/src/sources/TransactionStore.res.mjs +5 -86
  95. package/svm.schema.json +19 -0
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Source from "./Source.res.mjs";
4
- import * as Prometheus from "../Prometheus.res.mjs";
5
4
  import * as EventRouter from "./EventRouter.res.mjs";
6
5
  import * as Performance from "../bindings/Performance.res.mjs";
7
6
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
@@ -166,7 +165,7 @@ function parseDecoded(d) {
166
165
  };
167
166
  }
168
167
 
169
- function toSvmInstruction(instr, programName, instructionName, logs, block) {
168
+ function toSvmInstruction(instr, programName, instructionName, logs) {
170
169
  return {
171
170
  programName: programName,
172
171
  instructionName: instructionName,
@@ -180,8 +179,7 @@ function toSvmInstruction(instr, programName, instructionName, logs, block) {
180
179
  d4: instr.d4,
181
180
  d8: instr.d8,
182
181
  params: Stdlib_Option.map(instr.decoded, parseDecoded),
183
- logs: logs,
184
- block: block
182
+ logs: logs
185
183
  };
186
184
  }
187
185
 
@@ -248,13 +246,26 @@ function toQueryTxField(field) {
248
246
  }
249
247
  }
250
248
 
249
+ function toQueryBlockField(field) {
250
+ switch (field) {
251
+ case "height" :
252
+ return "block_height";
253
+ case "parentSlot" :
254
+ return "parent_slot";
255
+ case "parentHash" :
256
+ return "parent_blockhash";
257
+ default:
258
+ return;
259
+ }
260
+ }
261
+
251
262
  function make(param) {
252
- let eventConfigs = param.eventConfigs;
263
+ let onEventRegistrations = param.onEventRegistrations;
253
264
  let chain = param.chain;
254
- let name = "SvmHyperSync";
265
+ let eventConfigs = onEventRegistrations.map(reg => reg.eventConfig);
255
266
  let programSchemas = buildProgramSchemas(eventConfigs);
256
267
  let client = SvmHyperSyncClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, undefined, undefined, undefined, programSchemas.length !== 0 ? programSchemas : undefined);
257
- let match = EventRouter.fromSvmEventConfigsOrThrow(eventConfigs, chain);
268
+ let match = EventRouter.fromSvmEventConfigsOrThrow(onEventRegistrations, chain);
258
269
  let eventRouter = match[0];
259
270
  let orderingByProgram = {};
260
271
  match[1].forEach(o => {
@@ -288,15 +299,29 @@ function make(param) {
288
299
  return true;
289
300
  }
290
301
  });
302
+ let fields$1 = [
303
+ "slot",
304
+ "blockhash",
305
+ "block_time"
306
+ ];
307
+ let selected = new Set();
308
+ eventConfigs.forEach(cfg => {
309
+ cfg.selectedBlockFields.forEach(field => {
310
+ selected.add(field);
311
+ });
312
+ });
313
+ selected.forEach(field => {
314
+ let queryField = toQueryBlockField(field);
315
+ if (queryField !== undefined) {
316
+ fields$1.push(queryField);
317
+ return;
318
+ }
319
+ });
291
320
  let getItemsOrThrow = async (fromBlock, toBlock, param, contractNameByAddress, knownHeight, param$1, param$2, itemsTarget, retry, logger) => {
292
321
  let totalTimeRef = Performance.now();
293
322
  let pageFetchRef = Performance.now();
294
323
  let instructionSelections = buildInstructionSelections(eventConfigs);
295
- let fields_block = [
296
- "slot",
297
- "blockhash",
298
- "block_time"
299
- ];
324
+ let fields_block = fields$1;
300
325
  let fields_transaction = needsTransactions ? fields : undefined;
301
326
  let fields_log = needsLogs ? [
302
327
  "slot",
@@ -314,7 +339,7 @@ function make(param) {
314
339
  "pre_amount",
315
340
  "post_amount"
316
341
  ] : undefined;
317
- let fields$1 = {
342
+ let fields$2 = {
318
343
  block: fields_block,
319
344
  transaction: fields_transaction,
320
345
  log: fields_log,
@@ -322,7 +347,7 @@ function make(param) {
322
347
  };
323
348
  let query_toSlot = Stdlib_Option.map(toBlock, toBlock => toBlock + 1 | 0);
324
349
  let query_instructions = instructionSelections;
325
- let query_fields = fields$1;
350
+ let query_fields = fields$2;
326
351
  let query_maxNumInstructions = itemsTarget;
327
352
  let query = {
328
353
  fromSlot: fromBlock,
@@ -331,7 +356,6 @@ function make(param) {
331
356
  fields: query_fields,
332
357
  maxNumInstructions: query_maxNumInstructions
333
358
  };
334
- Prometheus.SourceRequestCount.increment(name, chain, "getInstructions");
335
359
  let match;
336
360
  try {
337
361
  match = await client.get(query);
@@ -354,6 +378,10 @@ function make(param) {
354
378
  }
355
379
  let resp = match[0];
356
380
  let pageFetchTime = Performance.secondsSince(pageFetchRef);
381
+ let requestStats = [{
382
+ method: "getInstructions",
383
+ seconds: pageFetchTime
384
+ }];
357
385
  let parsingRef = Performance.now();
358
386
  let blockTimeBySlot = {};
359
387
  resp.data.blocks.forEach(b => {
@@ -388,25 +416,18 @@ function make(param) {
388
416
  let contractAddress = instr.programId;
389
417
  let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress, contractNameByAddress);
390
418
  if (maybeConfig !== undefined) {
419
+ let eventConfig = maybeConfig.eventConfig;
391
420
  let logKey = instr.slot.toString() + ":" + instr.transactionIndex.toString() + ":" + serializeInstructionAddress(instr.instructionAddress);
392
421
  let maybeLogs = Stdlib_Option.map(logsByKey[logKey], logs => logs.map(log => ({
393
422
  kind: Stdlib_Option.getOr(log.kind, ""),
394
423
  message: Stdlib_Option.getOr(log.message, "")
395
424
  })));
396
- let slotKey = instr.slot.toString();
397
- let blockTime = blockTimeBySlot[slotKey];
398
- let payload = toSvmInstruction(instr, maybeConfig.contractName, maybeConfig.name, maybeConfig.includeLogs ? maybeLogs : undefined, {
399
- slot: instr.slot,
400
- time: Stdlib_Option.getOr(blockTime, 0),
401
- hash: ""
402
- });
425
+ let payload = toSvmInstruction(instr, eventConfig.contractName, eventConfig.name, eventConfig.includeLogs ? maybeLogs : undefined);
403
426
  parsedQueueItems.push({
404
427
  kind: 0,
405
- eventConfig: maybeConfig,
406
- timestamp: Stdlib_Option.getOr(blockTime, 0),
428
+ onEventRegistration: maybeConfig,
407
429
  chain: chain,
408
430
  blockNumber: instr.slot,
409
- blockHash: "",
410
431
  logIndex: synthLogIndex(instr),
411
432
  transactionIndex: instr.transactionIndex,
412
433
  payload: payload
@@ -426,6 +447,7 @@ function make(param) {
426
447
  blockHashes: blockHashes,
427
448
  parsedQueueItems: parsedQueueItems,
428
449
  transactionStore: Primitive_option.some(match[1]),
450
+ blockStore: Primitive_option.some(match[2]),
429
451
  fromBlockQueried: fromBlock,
430
452
  latestFetchedBlockNumber: highestSlot,
431
453
  latestFetchedBlockTimestamp: latestBlockTime,
@@ -433,11 +455,13 @@ function make(param) {
433
455
  "total time elapsed (s)": totalTimeElapsed,
434
456
  "parsing time (s)": parsingTimeElapsed,
435
457
  "page fetch time (s)": pageFetchTime
436
- }
458
+ },
459
+ requestStats: requestStats
437
460
  };
438
461
  };
439
462
  let queryBlockDataRange = async (fromSlot, toSlot) => {
440
463
  let blockDatas = [];
464
+ let requestStats = [];
441
465
  let fromRef = fromSlot;
442
466
  let keepGoing = true;
443
467
  while (keepGoing) {
@@ -458,9 +482,13 @@ function make(param) {
458
482
  fields: query_fields,
459
483
  maxNumBlocks: query_maxNumBlocks
460
484
  };
461
- Prometheus.SourceRequestCount.increment(name, chain, "getBlockHashes");
485
+ let timerRef = Performance.now();
462
486
  let match = await client.get(query);
463
487
  let resp = match[0];
488
+ requestStats.push({
489
+ method: "getBlockHashes",
490
+ seconds: Performance.secondsSince(timerRef)
491
+ });
464
492
  resp.data.blocks.forEach(b => {
465
493
  blockDatas.push({
466
494
  blockHash: b.blockhash,
@@ -474,14 +502,20 @@ function make(param) {
474
502
  fromRef = resp.nextSlot;
475
503
  }
476
504
  };
477
- return blockDatas;
505
+ return [
506
+ blockDatas,
507
+ requestStats
508
+ ];
478
509
  };
479
510
  let getBlockHashes = async (blockNumbers, param) => {
480
511
  let firstSlot = blockNumbers[0];
481
512
  if (firstSlot === undefined) {
482
513
  return {
483
- TAG: "Ok",
484
- _0: []
514
+ result: {
515
+ TAG: "Ok",
516
+ _0: []
517
+ },
518
+ requestStats: []
485
519
  };
486
520
  }
487
521
  try {
@@ -501,21 +535,27 @@ function make(param) {
501
535
  }
502
536
  requested.add(slot);
503
537
  });
504
- let blockDatas = await queryBlockDataRange(minSlot.contents, maxSlot.contents);
538
+ let match = await queryBlockDataRange(minSlot.contents, maxSlot.contents);
505
539
  return {
506
- TAG: "Ok",
507
- _0: blockDatas.filter(data => requested.delete(data.blockNumber))
540
+ result: {
541
+ TAG: "Ok",
542
+ _0: match[0].filter(data => requested.delete(data.blockNumber))
543
+ },
544
+ requestStats: match[1]
508
545
  };
509
546
  } catch (raw_exn) {
510
547
  let exn = Primitive_exceptions.internalToException(raw_exn);
511
548
  return {
512
- TAG: "Error",
513
- _0: exn
549
+ result: {
550
+ TAG: "Error",
551
+ _0: exn
552
+ },
553
+ requestStats: []
514
554
  };
515
555
  }
516
556
  };
517
557
  return {
518
- name: name,
558
+ name: "SvmHyperSync",
519
559
  sourceFor: "Sync",
520
560
  chain: chain,
521
561
  poweredByHyperSync: true,
@@ -523,11 +563,15 @@ function make(param) {
523
563
  getBlockHashes: getBlockHashes,
524
564
  getHeightOrThrow: async () => {
525
565
  let timer = Performance.now();
526
- let h = await client.getHeight();
566
+ let height = await client.getHeight();
527
567
  let seconds = Performance.secondsSince(timer);
528
- Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
529
- Prometheus.SourceRequestCount.addSeconds(name, chain, "getHeight", seconds);
530
- return h;
568
+ return {
569
+ height: height,
570
+ requestStats: [{
571
+ method: "getHeight",
572
+ seconds: seconds
573
+ }]
574
+ };
531
575
  },
532
576
  getItemsOrThrow: getItemsOrThrow
533
577
  };
@@ -542,6 +586,7 @@ export {
542
586
  toSvmInstruction,
543
587
  probeRouter,
544
588
  toQueryTxField,
589
+ toQueryBlockField,
545
590
  make,
546
591
  }
547
- /* Prometheus Not a pure module */
592
+ /* EventRouter Not a pure module */
@@ -21,42 +21,12 @@ let make = (~ecosystem: Ecosystem.name, ~shouldChecksum: bool): t => {
21
21
  }
22
22
  }
23
23
 
24
- // Field-name bit-index map from an ordered field-name array. The index is the
25
- // field code shared with the Rust store (`EvmTxField`/`SvmTxField`).
26
- let fieldCodes = (fields: array<string>): dict<int> => {
27
- let codes = Dict.make()
28
- fields->Array.forEachWithIndex((name, i) => codes->Dict.set(name, i))
29
- codes
30
- }
31
-
32
- let pow2: int => float = %raw(`c => Math.pow(2, c)`)
33
-
34
- // One event's selected transaction fields as a bitmask float (bit `code` set ⇔
35
- // selected). Each field appears once, so summing `pow2(code)` sets distinct bits
36
- // with no overlap; the result stays exact in f64 (codes span 0..31, so a mask is
37
- // at most 2^32-1).
38
- let maskFromFields = (selectedTransactionFields: Utils.Set.t<string>, ~codes: dict<int>): float => {
39
- let mask = ref(0.)
40
- selectedTransactionFields->Utils.Set.forEach(name =>
41
- switch codes->Utils.Dict.dangerouslyGetNonOption(name) {
42
- | Some(code) => mask := mask.contents +. pow2(code)
43
- | None => ()
44
- }
45
- )
46
- mask.contents
47
- }
48
-
49
- // Build an ecosystem's per-event mask function from its ordered field-name
50
- // array. The field codes are derived once and closed over.
51
- let makeMaskFn = (fields: array<string>): (Utils.Set.t<string> => float) => {
52
- let codes = fieldCodes(fields)
53
- selectedTransactionFields => selectedTransactionFields->maskFromFields(~codes)
54
- }
55
-
56
- // Bitwise OR of two per-event masks. Masks fit in 32 bits (≤32 transaction
57
- // fields), so `>>> 0` recovers the unsigned value that a plain `|` renders
58
- // negative once bit 31 is set.
59
- let orMask: (float, float) => float = %raw(`(a, b) => (a | b) >>> 0`)
24
+ // One event's selected transaction fields store selection bitmask, built from
25
+ // the ecosystem's ordered field-name array (the bit index is the field code
26
+ // shared with the Rust store, `EvmTxField`/`SvmTxField`).
27
+ let makeMaskFn = FieldMask.makeMaskFn
28
+ let orMask = FieldMask.orMask
29
+ let fieldCodes = FieldMask.fieldCodes
60
30
 
61
31
  // Drain another store (a fetch-response page) into this one.
62
32
  @send external merge: (t, t) => unit = "merge"
@@ -77,74 +47,3 @@ external materialize: (
77
47
 
78
48
  // Drop transactions for blocks above the given block (rolled back).
79
49
  @send external rollback: (t, int) => unit = "rollback"
80
-
81
- // Materialise each store-backed item's selected transaction fields and write the
82
- // resulting transaction onto its payload. Every event's mask comes from its own
83
- // `eventConfig.transactionFieldMask`, so a transaction decodes only the fields
84
- // the events on it selected — a large field (e.g. `input`) never materialises
85
- // for events that didn't ask for it. Items that already carry an inline
86
- // transaction (RPC/simulate/Fuel) are skipped. Store-backed items always get a
87
- // transaction object — the selected fields, or `{}` when nothing was selected —
88
- // so `event.transaction` is never `undefined` (matching the inline sources).
89
- // Deduped per (blockNumber, transactionIndex); each row's mask is the OR of the
90
- // masks of the events sharing that transaction.
91
- let materializeItems = async (store: t, ~items: array<Internal.item>) => {
92
- // Store-backed items arrive in (block, logIndex) order, and a transaction's
93
- // logs are contiguous within a block, so events sharing a (blockNumber,
94
- // transactionIndex) are adjacent regardless of event. Group them by extending
95
- // the current run rather than hashing a string key per item. A key recurring
96
- // non-adjacently just splits into two groups (one redundant decode) — never
97
- // incorrect.
98
- let blockNumbers = []
99
- let transactionIndices = []
100
- let masks = []
101
- let payloadGroups = []
102
- let anySelected = ref(false)
103
-
104
- items->Array.forEach(item =>
105
- switch item {
106
- | Internal.Event(_) =>
107
- let eventItem = item->Internal.castUnsafeEventItem
108
- switch eventItem.payload->Internal.getPayloadTransaction->Nullable.toOption {
109
- | Some(_) => () // RPC/simulate/Fuel carry the transaction inline.
110
- | None =>
111
- let {blockNumber, transactionIndex} = eventItem
112
- let mask = eventItem.eventConfig.transactionFieldMask
113
- if mask != 0. {
114
- anySelected := true
115
- }
116
- let last = payloadGroups->Array.length - 1
117
- if (
118
- last >= 0 &&
119
- blockNumbers->Array.getUnsafe(last) == blockNumber &&
120
- transactionIndices->Array.getUnsafe(last) == transactionIndex
121
- ) {
122
- payloadGroups->Array.getUnsafe(last)->Array.push(eventItem.payload)
123
- masks->Array.setUnsafe(last, orMask(masks->Array.getUnsafe(last), mask))
124
- } else {
125
- blockNumbers->Array.push(blockNumber)
126
- transactionIndices->Array.push(transactionIndex)
127
- masks->Array.push(mask)
128
- payloadGroups->Array.push([eventItem.payload])
129
- }
130
- }
131
- | Internal.Block(_) => ()
132
- }
133
- )
134
-
135
- if payloadGroups->Utils.Array.notEmpty {
136
- if anySelected.contents {
137
- let txs = await store->materialize(~blockNumbers, ~transactionIndices, ~masks)
138
- payloadGroups->Array.forEachWithIndex((payloads, i) => {
139
- let tx = txs->Array.getUnsafe(i)
140
- payloads->Array.forEach(payload => payload->Internal.setPayloadTransaction(tx))
141
- })
142
- } else {
143
- // No event selected any field: stamp an empty transaction object so
144
- // `event.transaction` is never undefined, without a materialize call.
145
- payloadGroups->Array.forEach(payloads =>
146
- payloads->Array.forEach(payload => payload->Internal.setPayloadTransaction(%raw(`{}`)))
147
- )
148
- }
149
- }
150
- }
@@ -1,7 +1,7 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Core from "../Core.res.mjs";
4
- import * as Utils from "../Utils.res.mjs";
4
+ import * as FieldMask from "./FieldMask.res.mjs";
5
5
 
6
6
  function make(ecosystem, shouldChecksum) {
7
7
  let ctor = Core.getAddon().TransactionStore;
@@ -15,97 +15,16 @@ function make(ecosystem, shouldChecksum) {
15
15
  }
16
16
  }
17
17
 
18
- function fieldCodes(fields) {
19
- let codes = {};
20
- fields.forEach((name, i) => {
21
- codes[name] = i;
22
- });
23
- return codes;
24
- }
25
-
26
- let pow2 = (c => Math.pow(2, c));
27
-
28
- function maskFromFields(selectedTransactionFields, codes) {
29
- let mask = {
30
- contents: 0
31
- };
32
- selectedTransactionFields.forEach(name => {
33
- let code = codes[name];
34
- if (code !== undefined) {
35
- mask.contents = mask.contents + pow2(code);
36
- return;
37
- }
38
- });
39
- return mask.contents;
40
- }
18
+ let makeMaskFn = FieldMask.makeMaskFn;
41
19
 
42
- function makeMaskFn(fields) {
43
- let codes = fieldCodes(fields);
44
- return selectedTransactionFields => maskFromFields(selectedTransactionFields, codes);
45
- }
20
+ let orMask = FieldMask.orMask;
46
21
 
47
- let orMask = ((a, b) => (a | b) >>> 0);
48
-
49
- async function materializeItems(store, items) {
50
- let blockNumbers = [];
51
- let transactionIndices = [];
52
- let masks = [];
53
- let payloadGroups = [];
54
- let anySelected = {
55
- contents: false
56
- };
57
- items.forEach(item => {
58
- if (item.kind !== 0) {
59
- return;
60
- }
61
- let match = item.payload.transaction;
62
- if (!(match == null)) {
63
- return;
64
- }
65
- let transactionIndex = item.transactionIndex;
66
- let blockNumber = item.blockNumber;
67
- let mask = item.eventConfig.transactionFieldMask;
68
- if (mask !== 0) {
69
- anySelected.contents = true;
70
- }
71
- let last = payloadGroups.length - 1 | 0;
72
- if (last >= 0 && blockNumbers[last] === blockNumber && transactionIndices[last] === transactionIndex) {
73
- payloadGroups[last].push(item.payload);
74
- masks[last] = orMask(masks[last], mask);
75
- } else {
76
- blockNumbers.push(blockNumber);
77
- transactionIndices.push(transactionIndex);
78
- masks.push(mask);
79
- payloadGroups.push([item.payload]);
80
- }
81
- });
82
- if (!Utils.$$Array.notEmpty(payloadGroups)) {
83
- return;
84
- }
85
- if (anySelected.contents) {
86
- let txs = await store.materialize(blockNumbers, transactionIndices, masks);
87
- payloadGroups.forEach((payloads, i) => {
88
- let tx = txs[i];
89
- payloads.forEach(payload => {
90
- payload.transaction = tx;
91
- });
92
- });
93
- return;
94
- }
95
- payloadGroups.forEach(payloads => {
96
- payloads.forEach(payload => {
97
- payload.transaction = {};
98
- });
99
- });
100
- }
22
+ let fieldCodes = FieldMask.fieldCodes;
101
23
 
102
24
  export {
103
25
  make,
104
- fieldCodes,
105
- pow2,
106
- maskFromFields,
107
26
  makeMaskFn,
108
27
  orMask,
109
- materializeItems,
28
+ fieldCodes,
110
29
  }
111
30
  /* Core Not a pure module */
package/svm.schema.json CHANGED
@@ -472,6 +472,16 @@
472
472
  "$ref": "#/$defs/SvmTransactionField"
473
473
  }
474
474
  },
475
+ "block_fields": {
476
+ "description": "Block fields to include on each matched instruction's `block`, as a list of field names. `slot`/`time`/`hash` are always included; this adds `height`/`parentSlot`/`parentHash`.",
477
+ "type": [
478
+ "array",
479
+ "null"
480
+ ],
481
+ "items": {
482
+ "$ref": "#/$defs/SvmBlockField"
483
+ }
484
+ },
475
485
  "log_fields": {
476
486
  "description": "Set to `true` to include program logs scoped to each matched instruction.",
477
487
  "type": [
@@ -505,6 +515,15 @@
505
515
  "version"
506
516
  ]
507
517
  },
518
+ "SvmBlockField": {
519
+ "description": "Selectable block field names (camelCase), matching the public\n`instruction.block` shape. `slot`/`time`/`hash` are always included,\nso everything here is opt-in on top of that trio.",
520
+ "type": "string",
521
+ "enum": [
522
+ "height",
523
+ "parentSlot",
524
+ "parentHash"
525
+ ]
526
+ },
508
527
  "ArgDef": {
509
528
  "description": "One named argument of an instruction. Mirrors\n`hypersync_client_solana::decode::NamedField`.",
510
529
  "type": "object",