envio 3.6.1 → 3.7.0-subgraph

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 (114) hide show
  1. package/index.d.ts +197 -9
  2. package/package.json +6 -6
  3. package/src/Batch.res +64 -25
  4. package/src/Batch.res.mjs +69 -46
  5. package/src/ChainFetching.res +13 -17
  6. package/src/ChainFetching.res.mjs +9 -14
  7. package/src/ChainState.res +160 -119
  8. package/src/ChainState.res.mjs +75 -46
  9. package/src/ChainState.resi +15 -12
  10. package/src/Config.res +18 -2
  11. package/src/Config.res.mjs +9 -6
  12. package/src/Core.res +20 -0
  13. package/src/Core.res.mjs +11 -0
  14. package/src/Ecosystem.res +0 -1
  15. package/src/Envio.res +16 -3
  16. package/src/EventConfigBuilder.res +155 -40
  17. package/src/EventConfigBuilder.res.mjs +76 -24
  18. package/src/EventProcessing.res +10 -14
  19. package/src/EventProcessing.res.mjs +12 -10
  20. package/src/EventUtils.res +3 -47
  21. package/src/FetchState.res +124 -104
  22. package/src/FetchState.res.mjs +116 -100
  23. package/src/HandlerLoader.res +20 -8
  24. package/src/HandlerLoader.res.mjs +11 -2
  25. package/src/HandlerRegister.res +108 -2
  26. package/src/HandlerRegister.res.mjs +59 -10
  27. package/src/HandlerRegister.resi +4 -0
  28. package/src/InMemoryStore.res +1 -6
  29. package/src/InMemoryStore.res.mjs +1 -3
  30. package/src/Internal.res +84 -24
  31. package/src/Internal.res.mjs +33 -2
  32. package/src/LazyLoader.res +12 -11
  33. package/src/LazyLoader.res.mjs +13 -7
  34. package/src/Main.res +22 -9
  35. package/src/Main.res.mjs +18 -5
  36. package/src/MemoryStorage.res +756 -0
  37. package/src/MemoryStorage.res.mjs +623 -0
  38. package/src/Persistence.res +4 -2
  39. package/src/PgStorage.res +24 -8
  40. package/src/PgStorage.res.mjs +15 -12
  41. package/src/ReorgDetection.res +0 -222
  42. package/src/ReorgDetection.res.mjs +0 -163
  43. package/src/Rollback.res +14 -15
  44. package/src/Rollback.res.mjs +4 -5
  45. package/src/SimulateItems.res +2 -2
  46. package/src/UserContext.res +358 -51
  47. package/src/UserContext.res.mjs +271 -35
  48. package/src/Utils.res +3 -0
  49. package/src/bindings/ClickHouse.res +16 -11
  50. package/src/bindings/ClickHouse.res.mjs +10 -10
  51. package/src/bindings/Vitest.res +1 -1
  52. package/src/sources/BlockStore.res +115 -5
  53. package/src/sources/BlockStore.res.mjs +25 -0
  54. package/src/sources/Evm.res +0 -1
  55. package/src/sources/Evm.res.mjs +0 -1
  56. package/src/sources/EvmHyperSyncSource.res +19 -84
  57. package/src/sources/EvmHyperSyncSource.res.mjs +24 -60
  58. package/src/sources/Fuel.res +24 -4
  59. package/src/sources/Fuel.res.mjs +23 -3
  60. package/src/sources/FuelHyperSync.res +8 -3
  61. package/src/sources/FuelHyperSync.res.mjs +5 -4
  62. package/src/sources/FuelHyperSync.resi +3 -1
  63. package/src/sources/FuelHyperSyncClient.res +7 -10
  64. package/src/sources/FuelHyperSyncSource.res +18 -45
  65. package/src/sources/FuelHyperSyncSource.res.mjs +18 -35
  66. package/src/sources/HyperSync.res +49 -229
  67. package/src/sources/HyperSync.res.mjs +74 -191
  68. package/src/sources/HyperSync.resi +11 -35
  69. package/src/sources/HyperSyncClient.res +9 -79
  70. package/src/sources/HyperSyncClient.res.mjs +2 -6
  71. package/src/sources/RequestStat.res +5 -0
  72. package/src/sources/RequestStat.res.mjs +2 -0
  73. package/src/sources/RpcSource.res +149 -43
  74. package/src/sources/RpcSource.res.mjs +104 -41
  75. package/src/sources/SimulateSource.res +8 -5
  76. package/src/sources/SimulateSource.res.mjs +6 -6
  77. package/src/sources/Source.res +89 -16
  78. package/src/sources/Source.res.mjs +50 -1
  79. package/src/sources/SourceManager.res +255 -50
  80. package/src/sources/SourceManager.res.mjs +149 -55
  81. package/src/sources/SourceManager.resi +2 -6
  82. package/src/sources/Svm.res +0 -7
  83. package/src/sources/Svm.res.mjs +0 -8
  84. package/src/sources/SvmHyperSyncClient.res +21 -16
  85. package/src/sources/SvmHyperSyncClient.res.mjs +3 -4
  86. package/src/sources/SvmHyperSyncSource.res +25 -117
  87. package/src/sources/SvmHyperSyncSource.res.mjs +8 -121
  88. package/src/subgraph/blocks.ts +176 -0
  89. package/src/subgraph/calls.ts +217 -0
  90. package/src/subgraph/conformance.ts +99 -0
  91. package/src/subgraph/division.ts +110 -0
  92. package/src/subgraph/errors.ts +90 -0
  93. package/src/subgraph/graph-ts-types/VERSION +2 -0
  94. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
  95. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
  96. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
  97. package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
  98. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
  99. package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
  100. package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
  101. package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
  102. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  103. package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
  104. package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
  105. package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
  106. package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
  107. package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
  108. package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
  109. package/src/subgraph/graph-ts-types/index.d.ts +102 -0
  110. package/src/subgraph/graph-ts.ts +1871 -0
  111. package/src/subgraph/hosts.ts +148 -0
  112. package/src/subgraph/runtime.ts +845 -0
  113. package/src/subgraph/scope.ts +63 -0
  114. package/svm.schema.json +3 -2
@@ -463,6 +463,21 @@ let makeFieldRegistry = (addressSchema: S.t<JSON.t>): Utils.Record.t<
463
463
  let fieldRegistryLowercase = makeFieldRegistry(lowercaseAddressSchema)
464
464
  let fieldRegistryChecksum = makeFieldRegistry(checksumAddressSchema)
465
465
 
466
+ // Whether an RPC source can populate a transaction field. The getter skips a
467
+ // field it can't parse, so this is what separates "absent because the chain has
468
+ // none" from "absent because RPC never provides it". `hash` and
469
+ // `transactionIndex` come off the log itself, so they have no registry entry.
470
+ // Blocks need no equivalent: `eth_getBlockByNumber` carries every block field,
471
+ // which `RpcFieldSelection_test.res` holds the registry to.
472
+ let isRpcTransactionField = (name: string) =>
473
+ switch name {
474
+ | "transactionIndex" | "hash" => true
475
+ | _ =>
476
+ fieldRegistryChecksum
477
+ ->Utils.Record.get(name->(Utils.magic: string => Internal.evmTransactionField))
478
+ ->Option.isSome
479
+ }
480
+
466
481
  type fetchStrategy = NoRpc | TransactionOnly | ReceiptOnly | TransactionAndReceipt
467
482
 
468
483
  // Parse fields from a raw JSON object into a result dict.
@@ -487,6 +502,30 @@ let parseFieldsFromJson = (
487
502
  })
488
503
  }
489
504
 
505
+ let effectiveGasPriceKey = (Internal.EffectiveGasPrice: Internal.evmTransactionField :> string)
506
+
507
+ // Pre-EIP-1559 receipts carry no `effectiveGasPrice` — every Optimism block
508
+ // below the Bedrock migration at 105235063, for one. Those chains price every
509
+ // transaction the legacy way, so the transaction's `gasPrice` is the effective
510
+ // price, which is the same substitution HyperSync serves for those blocks.
511
+ // Reads `gasPrice` but stores under `effectiveGasPrice`.
512
+ let effectiveGasPriceFallbackDef = {
513
+ location: EffectiveGasPrice,
514
+ jsonKey: "gasPrice",
515
+ schema: Rpc.hexBigintSchema->toFieldSchema,
516
+ source: TransactionOnly,
517
+ }
518
+
519
+ let fillEffectiveGasPriceOrThrow = (mutTransactionAcc: dict<JSON.t>, txJson: JSON.t) => {
520
+ let gasPrice =
521
+ txJson->(Utils.magic: JSON.t => dict<JSON.t>)->Utils.Dict.dangerouslyGetNonOption("gasPrice")
522
+ switch gasPrice {
523
+ | None =>
524
+ JsError.throwWithMessage(`Neither "effectiveGasPrice" nor "gasPrice" is present in the RPC response for the transaction. Remove "effectiveGasPrice" from the field selection, or index this chain via HyperSync.`)
525
+ | Some(_) => parseFieldsFromJson(mutTransactionAcc, [effectiveGasPriceFallbackDef], txJson)
526
+ }
527
+ }
528
+
490
529
  let makeThrowingGetEventTransaction = (
491
530
  ~getTransactionJson: string => promise<JSON.t>,
492
531
  ~getReceiptJson: string => promise<JSON.t>,
@@ -507,6 +546,7 @@ let makeThrowingGetEventTransaction = (
507
546
  // Classify fields: log-derived vs RPC fields
508
547
  let hasTransactionIndex = ref(false)
509
548
  let hasHash = ref(false)
549
+ let hasEffectiveGasPrice = ref(false)
510
550
  let txFields: array<fieldDef> = []
511
551
  let receiptFields: array<fieldDef> = []
512
552
  let bothFields: array<fieldDef> = []
@@ -518,6 +558,15 @@ let makeThrowingGetEventTransaction = (
518
558
  | _ =>
519
559
  switch fieldRegistry->Utils.Record.get(fieldName) {
520
560
  | Some(def) =>
561
+ // Absent from the receipt means fall back to the transaction's
562
+ // `gasPrice`, so this one field parses leniently rather than
563
+ // throwing on a receipt that omits it.
564
+ let def = if fieldName === EffectiveGasPrice {
565
+ hasEffectiveGasPrice := true
566
+ {...def, schema: S.nullable(def.schema)->toFieldSchema}
567
+ } else {
568
+ def
569
+ }
521
570
  switch def.source {
522
571
  | TransactionOnly => txFields->Array.push(def)->ignore
523
572
  | ReceiptOnly => receiptFields->Array.push(def)->ignore
@@ -580,10 +629,8 @@ let makeThrowingGetEventTransaction = (
580
629
  | _ => Promise.resolve(None)
581
630
  }
582
631
 
583
- Promise.all2((txJsonPromise, receiptJsonPromise))->Promise.thenResolve(((
584
- txJson,
585
- receiptJson,
586
- )) => {
632
+ Promise.all2((txJsonPromise, receiptJsonPromise))
633
+ ->Promise.then(((txJson, receiptJson)) => {
587
634
  let mutTransactionAcc = Dict.make()
588
635
  setLogFields(mutTransactionAcc, log)
589
636
 
@@ -596,6 +643,30 @@ let makeThrowingGetEventTransaction = (
596
643
  | None => ()
597
644
  }
598
645
 
646
+ // Only the chains that omit it pay for the extra request, and
647
+ // only when the receipt has already come back without it.
648
+ if (
649
+ hasEffectiveGasPrice.contents &&
650
+ mutTransactionAcc
651
+ ->Utils.Dict.dangerouslyGetNonOption(effectiveGasPriceKey)
652
+ ->Option.isNone
653
+ ) {
654
+ switch txJson {
655
+ | Some(json) => {
656
+ fillEffectiveGasPriceOrThrow(mutTransactionAcc, json)
657
+ Promise.resolve(mutTransactionAcc)
658
+ }
659
+ | None =>
660
+ getTransactionJson(log.transactionHash)->Promise.thenResolve(json => {
661
+ fillEffectiveGasPriceOrThrow(mutTransactionAcc, json)
662
+ mutTransactionAcc
663
+ })
664
+ }
665
+ } else {
666
+ Promise.resolve(mutTransactionAcc)
667
+ }
668
+ })
669
+ ->Promise.thenResolve(mutTransactionAcc => {
599
670
  mutTransactionAcc->(Utils.magic: dict<JSON.t> => 'a)
600
671
  })
601
672
  }
@@ -768,6 +839,12 @@ let make = (
768
839
  let transactionLoader = ref(makeTransactionLoader())
769
840
  let receiptLoader = ref(makeReceiptLoader())
770
841
 
842
+ let resetCachedLoaders = () => {
843
+ blockLoader := makeBlockLoader()
844
+ transactionLoader := makeTransactionLoader()
845
+ receiptLoader := makeReceiptLoader()
846
+ }
847
+
771
848
  let getEventBlockOrThrow = makeThrowingGetEventBlock(
772
849
  ~getBlockJson=blockNumber => blockLoader.contents->LazyLoader.get(blockNumber),
773
850
  ~lowercaseAddresses,
@@ -815,10 +892,16 @@ let make = (
815
892
  | None => knownHeight
816
893
  }
817
894
 
818
- let firstBlockParentPromise =
819
- fromBlock > 0
895
+ // The seam block (`fromBlock - 1`) is the only block this range shares with
896
+ // what the store already scanned, so it is where a reorg at the boundary
897
+ // shows up. Reading it directly would answer from the block cache — it was
898
+ // the previous range's `toBlock`, so it is always cached, and always on the
899
+ // chain that range saw. Read `fromBlock` instead, which no earlier range
900
+ // touched, and take the seam's hash from its `parentHash`.
901
+ let firstBlockPromise =
902
+ fromBlock > 0 && fromBlock <= toBlock
820
903
  ? blockLoader.contents
821
- ->LazyLoader.get(fromBlock - 1)
904
+ ->LazyLoader.get(fromBlock)
822
905
  ->Promise.thenResolve(json => Some(parseBlockInfo(json)))
823
906
  : Promise.resolve(None)
824
907
 
@@ -885,9 +968,13 @@ let make = (
885
968
  (
886
969
  async () => {
887
970
  let (block, transaction) = try await Promise.all2((
888
- log->getEventBlockOrThrow(~selectedBlockFields=eventConfig.selectedBlockFields),
971
+ log->getEventBlockOrThrow(
972
+ ~selectedBlockFields=onEventRegistration.fieldSelection.blockFields->(
973
+ Utils.magic: Utils.Set.t<string> => Utils.Set.t<Internal.evmBlockField>
974
+ ),
975
+ ),
889
976
  log->getEventTransactionOrThrow(
890
- ~selectedTransactionFields=eventConfig.selectedTransactionFields->(
977
+ ~selectedTransactionFields=onEventRegistration.fieldSelection.transactionFields->(
891
978
  Utils.magic: Utils.Set.t<string> => Utils.Set.t<Internal.evmTransactionField>
892
979
  ),
893
980
  ),
@@ -931,7 +1018,7 @@ let make = (
931
1018
  payload: {
932
1019
  contractName: eventConfig.contractName,
933
1020
  eventName: eventConfig.name,
934
- chainId: chainId,
1021
+ chainId,
935
1022
  params: decoded,
936
1023
  block,
937
1024
  transaction,
@@ -944,55 +1031,66 @@ let make = (
944
1031
  })
945
1032
  ->Promise.all
946
1033
 
947
- let optFirstBlockParent = await firstBlockParentPromise
1034
+ let optFirstBlock = await firstBlockPromise
948
1035
 
949
1036
  let totalTimeElapsed = startFetchingBatchTimeRef->Performance.secondsSince
950
1037
 
951
1038
  // Every fetched block carries `hash` and `parentHash`, so each one yields
952
1039
  // two confirmed (number, hash) pairs for reorg detection at no extra cost.
953
- let blockHashes = []
1040
+ // Both these blocks and the logs' own `blockHash` come from this range's
1041
+ // responses, never from the block cache's older view of the chain. They go
1042
+ // into a hash-only page store merged into the chain store, where hash
1043
+ // comparison happens. The block data itself stays inline on the payload.
1044
+ let observedBlocks: array<BlockStore.inputBlock> = []
954
1045
  let pushBlockInfo = (b: blockInfo) => {
955
- blockHashes->Array.push({ReorgDetection.blockNumber: b.number, blockHash: b.hash})->ignore
1046
+ observedBlocks
1047
+ ->Array.push({
1048
+ BlockStore.blockNumber: b.number,
1049
+ blockHash: b.hash,
1050
+ blockTimestamp: b.timestamp,
1051
+ })
1052
+ ->ignore
956
1053
  if b.number > 0 {
957
- blockHashes
958
- ->Array.push({ReorgDetection.blockNumber: b.number - 1, blockHash: b.parentHash})
1054
+ observedBlocks
1055
+ ->Array.push({BlockStore.blockNumber: b.number - 1, blockHash: b.parentHash})
959
1056
  ->ignore
960
1057
  }
961
1058
  }
962
1059
  pushBlockInfo(latestFetchedBlockInfo)
963
- switch optFirstBlockParent {
1060
+ switch optFirstBlock {
964
1061
  | Some(b) => pushBlockInfo(b)
965
1062
  | None => ()
966
1063
  }
967
1064
  items->Array.forEach(({log}) =>
968
- blockHashes
969
- ->Array.push({ReorgDetection.blockNumber: log.blockNumber, blockHash: log.blockHash})
1065
+ observedBlocks
1066
+ ->Array.push({BlockStore.blockNumber: log.blockNumber, blockHash: log.blockHash})
970
1067
  ->ignore
971
1068
  )
972
1069
 
973
1070
  {
974
- latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
975
1071
  latestFetchedBlockNumber: latestFetchedBlockInfo.number,
976
1072
  parsedQueueItems,
977
- // RPC keeps the transaction and block inline on the payload; no store pages.
1073
+ // RPC keeps the transaction and block inline on the payload; no
1074
+ // transaction page, and the block page carries only observed hashes.
978
1075
  transactionStore: None,
979
- blockStore: None,
1076
+ blockStore: BlockStore.fromJs(
1077
+ observedBlocks,
1078
+ ~ecosystem=Evm,
1079
+ ~shouldChecksum=!lowercaseAddresses,
1080
+ ),
980
1081
  stats: {
981
1082
  totalTimeElapsed: totalTimeElapsed,
982
1083
  },
983
1084
  knownHeight,
984
- blockHashes,
985
1085
  fromBlockQueried: fromBlock,
986
1086
  requestStats: drainRequestStats(),
987
1087
  }
988
1088
  }
989
1089
 
990
- let onReorg = (~rollbackTargetBlock as _) => {
991
- // Drop cached block/transaction/receipt data — after a reorg the cached
992
- // entries may refer to orphaned-chain values.
993
- blockLoader := makeBlockLoader()
994
- transactionLoader := makeTransactionLoader()
995
- receiptLoader := makeReceiptLoader()
1090
+ let onReorg = () => {
1091
+ // Drop cached block/transaction/receipt data — after a reorg or an
1092
+ // internally inconsistent response these may refer to orphaned-chain values.
1093
+ resetCachedLoaders()
996
1094
  }
997
1095
 
998
1096
  let getBlockHashes = (~blockNumbers, ~logger as _currentlyUnusedLogger) => {
@@ -1000,21 +1098,29 @@ let make = (
1000
1098
  ->Array.map(blockNum => blockLoader.contents->LazyLoader.get(blockNum))
1001
1099
  ->Promise.all
1002
1100
  ->Promise.thenResolve(rawBlocks => {
1003
- let result =
1004
- rawBlocks
1005
- ->Array.map(json => {
1006
- let b = parseBlockInfo(json)
1007
-
1008
- (
1009
- {
1010
- blockNumber: b.number,
1011
- blockHash: b.hash,
1012
- blockTimestamp: b.timestamp,
1013
- }: ReorgDetection.blockDataWithTimestamp
1014
- )
1101
+ // Each block is fetched in its own request, so responses can mix forks.
1102
+ // The parent hash becomes a minimal extra row: when consecutive blocks
1103
+ // are requested, the page's own hash-collision check cross-validates the
1104
+ // separately fetched responses.
1105
+ let observedBlocks: array<BlockStore.inputBlock> = []
1106
+ rawBlocks->Array.forEach(json => {
1107
+ let b = parseBlockInfo(json)
1108
+ observedBlocks
1109
+ ->Array.push({
1110
+ BlockStore.blockNumber: b.number,
1111
+ blockHash: b.hash,
1112
+ blockTimestamp: b.timestamp,
1015
1113
  })
1016
- ->Ok
1017
- {Source.result, requestStats: drainRequestStats()}
1114
+ ->ignore
1115
+ if b.number > 0 {
1116
+ observedBlocks
1117
+ ->Array.push({BlockStore.blockNumber: b.number - 1, blockHash: b.parentHash})
1118
+ ->ignore
1119
+ }
1120
+ })
1121
+ let blockStore =
1122
+ observedBlocks->BlockStore.fromJs(~ecosystem=Evm, ~shouldChecksum=!lowercaseAddresses)
1123
+ {Source.result: Ok(blockStore), requestStats: drainRequestStats()}
1018
1124
  })
1019
1125
  ->Promise.catch(exn =>
1020
1126
  {Source.result: Error(exn), requestStats: drainRequestStats()}->Promise.resolve
@@ -1023,7 +1129,7 @@ let make = (
1023
1129
 
1024
1130
  let createHeightSubscription =
1025
1131
  ws->Option.map(wsUrl =>
1026
- (~onHeight) => RpcWebSocketHeightStream.subscribe(~wsUrl, ~chainId=chainId, ~onHeight)
1132
+ (~onHeight) => RpcWebSocketHeightStream.subscribe(~wsUrl, ~chainId, ~onHeight)
1027
1133
  )
1028
1134
 
1029
1135
  {
@@ -9,6 +9,7 @@ import * as Address from "../Address.res.mjs";
9
9
  import * as ChainId from "../ChainId.res.mjs";
10
10
  import * as Logging from "../Logging.res.mjs";
11
11
  import * as Internal from "../Internal.res.mjs";
12
+ import * as BlockStore from "./BlockStore.res.mjs";
12
13
  import * as LazyLoader from "../LazyLoader.res.mjs";
13
14
  import * as Performance from "../bindings/Performance.res.mjs";
14
15
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
@@ -579,6 +580,16 @@ let fieldRegistryLowercase = makeFieldRegistry(lowercaseAddressSchema);
579
580
 
580
581
  let fieldRegistryChecksum = makeFieldRegistry(checksumAddressSchema);
581
582
 
583
+ function isRpcTransactionField(name) {
584
+ switch (name) {
585
+ case "hash" :
586
+ case "transactionIndex" :
587
+ return true;
588
+ default:
589
+ return Stdlib_Option.isSome(fieldRegistryChecksum[name]);
590
+ }
591
+ }
592
+
582
593
  function parseFieldsFromJson(mutTransactionAcc, fields, json) {
583
594
  fields.forEach(def => {
584
595
  let raw = json[def.jsonKey];
@@ -596,6 +607,22 @@ function parseFieldsFromJson(mutTransactionAcc, fields, json) {
596
607
  });
597
608
  }
598
609
 
610
+ let effectiveGasPriceFallbackDef = {
611
+ location: "effectiveGasPrice",
612
+ jsonKey: "gasPrice",
613
+ schema: Rpc.hexBigintSchema,
614
+ source: "TransactionOnly"
615
+ };
616
+
617
+ function fillEffectiveGasPriceOrThrow(mutTransactionAcc, txJson) {
618
+ let gasPrice = txJson["gasPrice"];
619
+ if (gasPrice !== undefined) {
620
+ return parseFieldsFromJson(mutTransactionAcc, [effectiveGasPriceFallbackDef], txJson);
621
+ } else {
622
+ return Stdlib_JsError.throwWithMessage(`Neither "effectiveGasPrice" nor "gasPrice" is present in the RPC response for the transaction. Remove "effectiveGasPrice" from the field selection, or index this chain via HyperSync.`);
623
+ }
624
+ }
625
+
599
626
  function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, lowercaseAddresses) {
600
627
  let fieldRegistry = lowercaseAddresses ? fieldRegistryLowercase : fieldRegistryChecksum;
601
628
  let fnsCache = new WeakMap();
@@ -611,6 +638,9 @@ function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, low
611
638
  let hasHash = {
612
639
  contents: false
613
640
  };
641
+ let hasEffectiveGasPrice = {
642
+ contents: false
643
+ };
614
644
  let txFields = [];
615
645
  let receiptFields = [];
616
646
  let bothFields = [];
@@ -627,16 +657,22 @@ function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, low
627
657
  if (def === undefined) {
628
658
  return;
629
659
  }
630
- let match = def.source;
660
+ let def$1 = fieldName === "effectiveGasPrice" ? (hasEffectiveGasPrice.contents = true, {
661
+ location: def.location,
662
+ jsonKey: def.jsonKey,
663
+ schema: S$RescriptSchema.nullable(def.schema),
664
+ source: def.source
665
+ }) : def;
666
+ let match = def$1.source;
631
667
  switch (match) {
632
668
  case "TransactionOnly" :
633
- txFields.push(def);
669
+ txFields.push(def$1);
634
670
  return;
635
671
  case "ReceiptOnly" :
636
- receiptFields.push(def);
672
+ receiptFields.push(def$1);
637
673
  return;
638
674
  case "Both" :
639
- bothFields.push(def);
675
+ bothFields.push(def$1);
640
676
  return;
641
677
  }
642
678
  }
@@ -713,8 +749,20 @@ function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, low
713
749
  if (receiptJson !== undefined) {
714
750
  parseFieldsFromJson(mutTransactionAcc, receiptFields, receiptJson);
715
751
  }
716
- return mutTransactionAcc;
717
- });
752
+ if (hasEffectiveGasPrice.contents && Stdlib_Option.isNone(mutTransactionAcc["effectiveGasPrice"])) {
753
+ if (txJson !== undefined) {
754
+ fillEffectiveGasPriceOrThrow(mutTransactionAcc, txJson);
755
+ return Promise.resolve(mutTransactionAcc);
756
+ } else {
757
+ return getTransactionJson(log.transactionHash).then(json => {
758
+ fillEffectiveGasPriceOrThrow(mutTransactionAcc, json);
759
+ return mutTransactionAcc;
760
+ });
761
+ }
762
+ } else {
763
+ return Promise.resolve(mutTransactionAcc);
764
+ }
765
+ }).then(mutTransactionAcc => mutTransactionAcc);
718
766
  }
719
767
  );
720
768
  fnsCache.set(selectedTransactionFields, fn$1);
@@ -799,6 +847,11 @@ function make(param) {
799
847
  let receiptLoader = {
800
848
  contents: makeReceiptLoader()
801
849
  };
850
+ let resetCachedLoaders = () => {
851
+ blockLoader.contents = makeBlockLoader();
852
+ transactionLoader.contents = makeTransactionLoader();
853
+ receiptLoader.contents = makeReceiptLoader();
854
+ };
802
855
  let getEventBlockOrThrow = makeThrowingGetEventBlock(blockNumber => LazyLoader.get(blockLoader.contents, blockNumber), lowercaseAddresses);
803
856
  let getEventTransactionOrThrow = makeThrowingGetEventTransaction(async transactionHash => {
804
857
  let json = await LazyLoader.get(transactionLoader.contents, transactionHash);
@@ -824,7 +877,7 @@ function make(param) {
824
877
  let getItemsOrThrow = async (fromBlock, toBlock, addressSet, knownHeight, partitionId, selection, param, retry, param$1) => {
825
878
  let startFetchingBatchTimeRef = Performance.now();
826
879
  let toBlock$1 = toBlock !== undefined ? Primitive_int.min(toBlock, knownHeight) : knownHeight;
827
- let firstBlockParentPromise = fromBlock > 0 ? LazyLoader.get(blockLoader.contents, fromBlock - 1 | 0).then(json => parseBlockInfo(json)) : Promise.resolve(undefined);
880
+ let firstBlockPromise = fromBlock > 0 && fromBlock <= toBlock$1 ? LazyLoader.get(blockLoader.contents, fromBlock).then(json => parseBlockInfo(json)) : Promise.resolve(undefined);
828
881
  if (Utils.$$Array.isEmpty(selection.onEventRegistrations)) {
829
882
  throw {
830
883
  RE_EXN_ID: Source.GetItemsError,
@@ -887,8 +940,8 @@ function make(param) {
887
940
  let match;
888
941
  try {
889
942
  match = await Promise.all([
890
- getEventBlockOrThrow(log, eventConfig.selectedBlockFields),
891
- getEventTransactionOrThrow(log, eventConfig.selectedTransactionFields)
943
+ getEventBlockOrThrow(log, onEventRegistration.fieldSelection.blockFields),
944
+ getEventTransactionOrThrow(log, onEventRegistration.fieldSelection.transactionFields)
892
945
  ]);
893
946
  } catch (raw_exn) {
894
947
  let exn = Primitive_exceptions.internalToException(raw_exn);
@@ -942,67 +995,71 @@ function make(param) {
942
995
  };
943
996
  })();
944
997
  }));
945
- let optFirstBlockParent = await firstBlockParentPromise;
998
+ let optFirstBlock = await firstBlockPromise;
946
999
  let totalTimeElapsed = Performance.secondsSince(startFetchingBatchTimeRef);
947
- let blockHashes = [];
1000
+ let observedBlocks = [];
948
1001
  let pushBlockInfo = b => {
949
- blockHashes.push({
1002
+ observedBlocks.push({
1003
+ blockNumber: b.number,
950
1004
  blockHash: b.hash,
951
- blockNumber: b.number
1005
+ blockTimestamp: b.timestamp
952
1006
  });
953
1007
  if (b.number > 0) {
954
- blockHashes.push({
955
- blockHash: b.parentHash,
956
- blockNumber: b.number - 1 | 0
1008
+ observedBlocks.push({
1009
+ blockNumber: b.number - 1 | 0,
1010
+ blockHash: b.parentHash
957
1011
  });
958
1012
  return;
959
1013
  }
960
1014
  };
961
1015
  pushBlockInfo(latestFetchedBlockInfo);
962
- if (optFirstBlockParent !== undefined) {
963
- pushBlockInfo(optFirstBlockParent);
1016
+ if (optFirstBlock !== undefined) {
1017
+ pushBlockInfo(optFirstBlock);
964
1018
  }
965
1019
  items.forEach(param => {
966
1020
  let log = param.log;
967
- blockHashes.push({
968
- blockHash: log.blockHash,
969
- blockNumber: log.blockNumber
1021
+ observedBlocks.push({
1022
+ blockNumber: log.blockNumber,
1023
+ blockHash: log.blockHash
970
1024
  });
971
1025
  });
972
1026
  return {
973
1027
  knownHeight: knownHeight,
974
- blockHashes: blockHashes,
975
1028
  parsedQueueItems: parsedQueueItems,
976
1029
  transactionStore: undefined,
977
- blockStore: undefined,
1030
+ blockStore: BlockStore.fromJs(observedBlocks, "evm", !lowercaseAddresses),
978
1031
  fromBlockQueried: fromBlock,
979
1032
  latestFetchedBlockNumber: latestFetchedBlockInfo.number,
980
- latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
981
1033
  stats: {
982
1034
  "total time elapsed (s)": totalTimeElapsed
983
1035
  },
984
1036
  requestStats: drainRequestStats()
985
1037
  };
986
1038
  };
987
- let onReorg = param => {
988
- blockLoader.contents = makeBlockLoader();
989
- transactionLoader.contents = makeTransactionLoader();
990
- receiptLoader.contents = makeReceiptLoader();
991
- };
1039
+ let onReorg = () => resetCachedLoaders();
992
1040
  let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => {
993
- let result = {
994
- TAG: "Ok",
995
- _0: rawBlocks.map(json => {
996
- let b = parseBlockInfo(json);
997
- return {
998
- blockHash: b.hash,
999
- blockNumber: b.number,
1000
- blockTimestamp: b.timestamp
1001
- };
1002
- })
1003
- };
1041
+ let observedBlocks = [];
1042
+ rawBlocks.forEach(json => {
1043
+ let b = parseBlockInfo(json);
1044
+ observedBlocks.push({
1045
+ blockNumber: b.number,
1046
+ blockHash: b.hash,
1047
+ blockTimestamp: b.timestamp
1048
+ });
1049
+ if (b.number > 0) {
1050
+ observedBlocks.push({
1051
+ blockNumber: b.number - 1 | 0,
1052
+ blockHash: b.parentHash
1053
+ });
1054
+ return;
1055
+ }
1056
+ });
1057
+ let blockStore = BlockStore.fromJs(observedBlocks, "evm", !lowercaseAddresses);
1004
1058
  return {
1005
- result: result,
1059
+ result: {
1060
+ TAG: "Ok",
1061
+ _0: blockStore
1062
+ },
1006
1063
  requestStats: drainRequestStats()
1007
1064
  };
1008
1065
  }), exn => Promise.resolve({
@@ -1041,6 +1098,8 @@ function make(param) {
1041
1098
  };
1042
1099
  }
1043
1100
 
1101
+ let effectiveGasPriceKey = "effectiveGasPrice";
1102
+
1044
1103
  export {
1045
1104
  TransactionDataNotFound,
1046
1105
  getKnownRawBlock,
@@ -1058,7 +1117,11 @@ export {
1058
1117
  makeFieldRegistry,
1059
1118
  fieldRegistryLowercase,
1060
1119
  fieldRegistryChecksum,
1120
+ isRpcTransactionField,
1061
1121
  parseFieldsFromJson,
1122
+ effectiveGasPriceKey,
1123
+ effectiveGasPriceFallbackDef,
1124
+ fillEffectiveGasPriceOrThrow,
1062
1125
  makeThrowingGetEventTransaction,
1063
1126
  make,
1064
1127
  }
@@ -3,6 +3,7 @@ let make = (
3
3
  ~endBlock: int,
4
4
  ~chainId: ChainId.t,
5
5
  ~addressStore: AddressStore.t,
6
+ ~ecosystem: Ecosystem.name=Evm,
6
7
  ): Source.t => {
7
8
  let reportedHeight = max(endBlock, 1)
8
9
 
@@ -13,7 +14,10 @@ let make = (
13
14
  poweredByHyperSync: false,
14
15
  pollingInterval: 0,
15
16
  getBlockHashes: (~blockNumbers as _, ~logger as _) => {
16
- Promise.resolve({Source.result: Ok([]), requestStats: []})
17
+ Promise.resolve({
18
+ Source.result: Ok(BlockStore.fromJs([], ~ecosystem, ~shouldChecksum=false)),
19
+ requestStats: [],
20
+ })
17
21
  },
18
22
  getHeightOrThrow: () => {
19
23
  // Report at least height 1 so the engine doesn't treat 0 as "no blocks available"
@@ -101,14 +105,13 @@ let make = (
101
105
 
102
106
  Promise.resolve({
103
107
  Source.knownHeight: reportedHeight,
104
- blockHashes: [],
105
108
  parsedQueueItems,
106
- // Simulate keeps the transaction and block inline on the payload; no store pages.
109
+ // Simulate keeps the transaction and block inline on the payload; no
110
+ // transaction page and an empty block page (nothing to reorg-check).
107
111
  transactionStore: None,
108
- blockStore: None,
112
+ blockStore: BlockStore.fromJs([], ~ecosystem, ~shouldChecksum=false),
109
113
  fromBlockQueried: fromBlock,
110
114
  latestFetchedBlockNumber: toBlockQueried,
111
- latestFetchedBlockTimestamp: 0,
112
115
  stats: {
113
116
  totalTimeElapsed: 0.,
114
117
  },
@@ -1,8 +1,10 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as BlockStore from "./BlockStore.res.mjs";
3
4
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
4
5
 
5
- function make(items, endBlock, chainId, addressStore) {
6
+ function make(items, endBlock, chainId, addressStore, ecosystemOpt) {
7
+ let ecosystem = ecosystemOpt !== undefined ? ecosystemOpt : "evm";
6
8
  let reportedHeight = Primitive_int.max(endBlock, 1);
7
9
  return {
8
10
  name: "SimulateSource",
@@ -13,7 +15,7 @@ function make(items, endBlock, chainId, addressStore) {
13
15
  getBlockHashes: (param, param$1) => Promise.resolve({
14
16
  result: {
15
17
  TAG: "Ok",
16
- _0: []
18
+ _0: BlockStore.fromJs([], ecosystem, false)
17
19
  },
18
20
  requestStats: []
19
21
  }),
@@ -72,13 +74,11 @@ function make(items, endBlock, chainId, addressStore) {
72
74
  });
73
75
  return Promise.resolve({
74
76
  knownHeight: reportedHeight,
75
- blockHashes: [],
76
77
  parsedQueueItems: parsedQueueItems,
77
78
  transactionStore: undefined,
78
- blockStore: undefined,
79
+ blockStore: BlockStore.fromJs([], ecosystem, false),
79
80
  fromBlockQueried: fromBlock,
80
81
  latestFetchedBlockNumber: toBlockQueried,
81
- latestFetchedBlockTimestamp: 0,
82
82
  stats: {
83
83
  "total time elapsed (s)": 0
84
84
  },
@@ -91,4 +91,4 @@ function make(items, endBlock, chainId, addressStore) {
91
91
  export {
92
92
  make,
93
93
  }
94
- /* No side effect */
94
+ /* BlockStore Not a pure module */