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.
- package/index.d.ts +197 -9
- package/package.json +6 -6
- package/src/Batch.res +64 -25
- package/src/Batch.res.mjs +69 -46
- package/src/ChainFetching.res +13 -17
- package/src/ChainFetching.res.mjs +9 -14
- package/src/ChainState.res +160 -119
- package/src/ChainState.res.mjs +75 -46
- package/src/ChainState.resi +15 -12
- package/src/Config.res +18 -2
- package/src/Config.res.mjs +9 -6
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +11 -0
- package/src/Ecosystem.res +0 -1
- package/src/Envio.res +16 -3
- package/src/EventConfigBuilder.res +155 -40
- package/src/EventConfigBuilder.res.mjs +76 -24
- package/src/EventProcessing.res +10 -14
- package/src/EventProcessing.res.mjs +12 -10
- package/src/EventUtils.res +3 -47
- package/src/FetchState.res +124 -104
- package/src/FetchState.res.mjs +116 -100
- package/src/HandlerLoader.res +20 -8
- package/src/HandlerLoader.res.mjs +11 -2
- package/src/HandlerRegister.res +108 -2
- package/src/HandlerRegister.res.mjs +59 -10
- package/src/HandlerRegister.resi +4 -0
- package/src/InMemoryStore.res +1 -6
- package/src/InMemoryStore.res.mjs +1 -3
- package/src/Internal.res +84 -24
- package/src/Internal.res.mjs +33 -2
- package/src/LazyLoader.res +12 -11
- package/src/LazyLoader.res.mjs +13 -7
- package/src/Main.res +22 -9
- package/src/Main.res.mjs +18 -5
- package/src/MemoryStorage.res +756 -0
- package/src/MemoryStorage.res.mjs +623 -0
- package/src/Persistence.res +4 -2
- package/src/PgStorage.res +24 -8
- package/src/PgStorage.res.mjs +15 -12
- package/src/ReorgDetection.res +0 -222
- package/src/ReorgDetection.res.mjs +0 -163
- package/src/Rollback.res +14 -15
- package/src/Rollback.res.mjs +4 -5
- package/src/SimulateItems.res +2 -2
- package/src/UserContext.res +358 -51
- package/src/UserContext.res.mjs +271 -35
- package/src/Utils.res +3 -0
- package/src/bindings/ClickHouse.res +16 -11
- package/src/bindings/ClickHouse.res.mjs +10 -10
- package/src/bindings/Vitest.res +1 -1
- package/src/sources/BlockStore.res +115 -5
- package/src/sources/BlockStore.res.mjs +25 -0
- package/src/sources/Evm.res +0 -1
- package/src/sources/Evm.res.mjs +0 -1
- package/src/sources/EvmHyperSyncSource.res +19 -84
- package/src/sources/EvmHyperSyncSource.res.mjs +24 -60
- package/src/sources/Fuel.res +24 -4
- package/src/sources/Fuel.res.mjs +23 -3
- package/src/sources/FuelHyperSync.res +8 -3
- package/src/sources/FuelHyperSync.res.mjs +5 -4
- package/src/sources/FuelHyperSync.resi +3 -1
- package/src/sources/FuelHyperSyncClient.res +7 -10
- package/src/sources/FuelHyperSyncSource.res +18 -45
- package/src/sources/FuelHyperSyncSource.res.mjs +18 -35
- package/src/sources/HyperSync.res +49 -229
- package/src/sources/HyperSync.res.mjs +74 -191
- package/src/sources/HyperSync.resi +11 -35
- package/src/sources/HyperSyncClient.res +9 -79
- package/src/sources/HyperSyncClient.res.mjs +2 -6
- package/src/sources/RequestStat.res +5 -0
- package/src/sources/RequestStat.res.mjs +2 -0
- package/src/sources/RpcSource.res +149 -43
- package/src/sources/RpcSource.res.mjs +104 -41
- package/src/sources/SimulateSource.res +8 -5
- package/src/sources/SimulateSource.res.mjs +6 -6
- package/src/sources/Source.res +89 -16
- package/src/sources/Source.res.mjs +50 -1
- package/src/sources/SourceManager.res +255 -50
- package/src/sources/SourceManager.res.mjs +149 -55
- package/src/sources/SourceManager.resi +2 -6
- package/src/sources/Svm.res +0 -7
- package/src/sources/Svm.res.mjs +0 -8
- package/src/sources/SvmHyperSyncClient.res +21 -16
- package/src/sources/SvmHyperSyncClient.res.mjs +3 -4
- package/src/sources/SvmHyperSyncSource.res +25 -117
- package/src/sources/SvmHyperSyncSource.res.mjs +8 -121
- package/src/subgraph/blocks.ts +176 -0
- package/src/subgraph/calls.ts +217 -0
- package/src/subgraph/conformance.ts +99 -0
- package/src/subgraph/division.ts +110 -0
- package/src/subgraph/errors.ts +90 -0
- package/src/subgraph/graph-ts-types/VERSION +2 -0
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
- package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
- package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
- package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
- package/src/subgraph/graph-ts-types/index.d.ts +102 -0
- package/src/subgraph/graph-ts.ts +1871 -0
- package/src/subgraph/hosts.ts +148 -0
- package/src/subgraph/runtime.ts +845 -0
- package/src/subgraph/scope.ts +63 -0
- 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))
|
|
584
|
-
|
|
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
|
-
|
|
819
|
-
|
|
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
|
|
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(
|
|
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=
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
958
|
-
->Array.push({
|
|
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
|
|
1060
|
+
switch optFirstBlock {
|
|
964
1061
|
| Some(b) => pushBlockInfo(b)
|
|
965
1062
|
| None => ()
|
|
966
1063
|
}
|
|
967
1064
|
items->Array.forEach(({log}) =>
|
|
968
|
-
|
|
969
|
-
->Array.push({
|
|
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
|
|
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:
|
|
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 = (
|
|
991
|
-
// Drop cached block/transaction/receipt data — after a reorg
|
|
992
|
-
//
|
|
993
|
-
|
|
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
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
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
|
-
->
|
|
1017
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
891
|
-
getEventTransactionOrThrow(log,
|
|
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
|
|
998
|
+
let optFirstBlock = await firstBlockPromise;
|
|
946
999
|
let totalTimeElapsed = Performance.secondsSince(startFetchingBatchTimeRef);
|
|
947
|
-
let
|
|
1000
|
+
let observedBlocks = [];
|
|
948
1001
|
let pushBlockInfo = b => {
|
|
949
|
-
|
|
1002
|
+
observedBlocks.push({
|
|
1003
|
+
blockNumber: b.number,
|
|
950
1004
|
blockHash: b.hash,
|
|
951
|
-
|
|
1005
|
+
blockTimestamp: b.timestamp
|
|
952
1006
|
});
|
|
953
1007
|
if (b.number > 0) {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
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 (
|
|
963
|
-
pushBlockInfo(
|
|
1016
|
+
if (optFirstBlock !== undefined) {
|
|
1017
|
+
pushBlockInfo(optFirstBlock);
|
|
964
1018
|
}
|
|
965
1019
|
items.forEach(param => {
|
|
966
1020
|
let log = param.log;
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
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:
|
|
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 =
|
|
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
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
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:
|
|
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({
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
/*
|
|
94
|
+
/* BlockStore Not a pure module */
|