envio 3.2.1 → 3.3.0-alpha.1
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/package.json +6 -7
- package/src/Batch.res +12 -15
- package/src/Batch.res.mjs +4 -5
- package/src/BatchProcessing.res +199 -0
- package/src/BatchProcessing.res.mjs +125 -0
- package/src/ChainFetching.res +373 -0
- package/src/ChainFetching.res.mjs +206 -0
- package/src/ChainMetadata.res +27 -0
- package/src/ChainMetadata.res.mjs +27 -0
- package/src/ChainState.res +643 -0
- package/src/ChainState.res.mjs +476 -0
- package/src/ChainState.resi +87 -0
- package/src/Config.res +13 -4
- package/src/Config.res.mjs +8 -3
- package/src/ContractRegisterContext.res +106 -0
- package/src/ContractRegisterContext.res.mjs +76 -0
- package/src/Core.res +3 -0
- package/src/CrossChainState.res +294 -0
- package/src/CrossChainState.res.mjs +221 -0
- package/src/CrossChainState.resi +39 -0
- package/src/Ecosystem.res +58 -0
- package/src/Ecosystem.res.mjs +43 -1
- package/src/Env.res +0 -2
- package/src/Env.res.mjs +0 -3
- package/src/EventConfigBuilder.res +2 -2
- package/src/EventProcessing.res +60 -46
- package/src/EventProcessing.res.mjs +33 -32
- package/src/EventUtils.res +0 -4
- package/src/EventUtils.res.mjs +0 -4
- package/src/ExitOnCaughtUp.res +10 -0
- package/src/ExitOnCaughtUp.res.mjs +22 -0
- package/src/FetchState.res +205 -73
- package/src/FetchState.res.mjs +242 -103
- package/src/InMemoryStore.res +36 -451
- package/src/InMemoryStore.res.mjs +20 -369
- package/src/IndexerLoop.res +43 -0
- package/src/IndexerLoop.res.mjs +46 -0
- package/src/IndexerState.res +536 -0
- package/src/IndexerState.res.mjs +543 -0
- package/src/IndexerState.resi +128 -0
- package/src/Internal.res +29 -8
- package/src/LoadLayer.res +20 -18
- package/src/LoadLayer.res.mjs +14 -12
- package/src/LoadLayer.resi +6 -3
- package/src/Logging.res +11 -44
- package/src/Logging.res.mjs +10 -42
- package/src/Main.res +54 -79
- package/src/Main.res.mjs +44 -56
- package/src/PgStorage.res +8 -71
- package/src/PgStorage.res.mjs +3 -47
- package/src/Prometheus.res +1 -13
- package/src/Prometheus.res.mjs +84 -96
- package/src/PruneStaleHistory.res +45 -0
- package/src/PruneStaleHistory.res.mjs +46 -0
- package/src/RawEvent.res +73 -0
- package/src/RawEvent.res.mjs +51 -0
- package/src/Rollback.res +204 -0
- package/src/Rollback.res.mjs +118 -0
- package/src/SimulateItems.res +12 -10
- package/src/SimulateItems.res.mjs +1 -1
- package/src/UserContext.res +26 -114
- package/src/UserContext.res.mjs +15 -78
- package/src/Writing.res +242 -0
- package/src/Writing.res.mjs +215 -0
- package/src/db/InternalTable.res +14 -27
- package/src/sources/Evm.res +40 -1
- package/src/sources/Evm.res.mjs +94 -84
- package/src/sources/Fuel.res +40 -1
- package/src/sources/Fuel.res.mjs +36 -26
- package/src/sources/HyperFuel.res +41 -120
- package/src/sources/HyperFuel.res.mjs +42 -80
- package/src/sources/HyperFuel.resi +1 -24
- package/src/sources/HyperFuelClient.res +16 -297
- package/src/sources/HyperFuelClient.res.mjs +5 -4
- package/src/sources/HyperFuelSource.res +33 -8
- package/src/sources/HyperFuelSource.res.mjs +56 -10
- package/src/sources/HyperSyncSource.res +5 -3
- package/src/sources/HyperSyncSource.res.mjs +1 -1
- package/src/sources/RpcSource.res +2 -2
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/SourceManager.res +14 -23
- package/src/sources/SourceManager.res.mjs +27 -29
- package/src/sources/SourceManager.resi +4 -2
- package/src/sources/Svm.res +18 -1
- package/src/sources/Svm.res.mjs +30 -22
- package/src/sources/SvmHyperSyncSource.res +1 -1
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/src/tui/Tui.res +38 -36
- package/src/tui/Tui.res.mjs +51 -51
- package/src/ChainFetcher.res +0 -519
- package/src/ChainFetcher.res.mjs +0 -314
- package/src/ChainManager.res +0 -358
- package/src/ChainManager.res.mjs +0 -291
- package/src/Ctx.res +0 -6
- package/src/Ctx.res.mjs +0 -2
- package/src/GlobalState.res +0 -1056
- package/src/GlobalState.res.mjs +0 -1086
- package/src/GlobalStateManager.res +0 -57
- package/src/GlobalStateManager.res.mjs +0 -68
- package/src/GlobalStateManager.resi +0 -7
- package/src/Ports.res +0 -5
- package/src/Ports.res.mjs +0 -9
- package/src/adapters/MarkBatchProcessedAdapter.res +0 -5
- package/src/adapters/MarkBatchProcessedAdapter.res.mjs +0 -14
- package/src/sources/EnvioApiClient.res +0 -15
- package/src/sources/EnvioApiClient.res.mjs +0 -24
package/src/db/InternalTable.res
CHANGED
|
@@ -571,33 +571,20 @@ GROUP BY "${(#chain_id: field :> string)}";`
|
|
|
571
571
|
}
|
|
572
572
|
|
|
573
573
|
module RawEvents = {
|
|
574
|
-
type t =
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
let schema = S.schema(s => {
|
|
590
|
-
chainId: s.matches(S.int),
|
|
591
|
-
eventId: s.matches(S.bigint),
|
|
592
|
-
eventName: s.matches(S.string),
|
|
593
|
-
contractName: s.matches(S.string),
|
|
594
|
-
blockNumber: s.matches(S.int),
|
|
595
|
-
logIndex: s.matches(S.int),
|
|
596
|
-
srcAddress: s.matches(Address.schema),
|
|
597
|
-
blockHash: s.matches(S.string),
|
|
598
|
-
blockTimestamp: s.matches(S.int),
|
|
599
|
-
blockFields: s.matches(S.json(~validate=false)),
|
|
600
|
-
transactionFields: s.matches(S.json(~validate=false)),
|
|
574
|
+
type t = Internal.rawEvent
|
|
575
|
+
|
|
576
|
+
let schema = S.schema((s): t => {
|
|
577
|
+
chain_id: s.matches(S.int),
|
|
578
|
+
event_id: s.matches(S.bigint),
|
|
579
|
+
event_name: s.matches(S.string),
|
|
580
|
+
contract_name: s.matches(S.string),
|
|
581
|
+
block_number: s.matches(S.int),
|
|
582
|
+
log_index: s.matches(S.int),
|
|
583
|
+
src_address: s.matches(Address.schema),
|
|
584
|
+
block_hash: s.matches(S.string),
|
|
585
|
+
block_timestamp: s.matches(S.int),
|
|
586
|
+
block_fields: s.matches(S.json(~validate=false)),
|
|
587
|
+
transaction_fields: s.matches(S.json(~validate=false)),
|
|
601
588
|
params: s.matches(S.json(~validate=false)),
|
|
602
589
|
})
|
|
603
590
|
|
package/src/sources/Evm.res
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
+
// EVM's concrete item payload. Erased to `Internal.eventPayload` on the item
|
|
2
|
+
// and recovered here via `toPayload`.
|
|
3
|
+
type payload = {
|
|
4
|
+
contractName: string,
|
|
5
|
+
eventName: string,
|
|
6
|
+
params: Internal.eventParams,
|
|
7
|
+
chainId: int,
|
|
8
|
+
srcAddress: Address.t,
|
|
9
|
+
logIndex: int,
|
|
10
|
+
transaction: Internal.eventTransaction,
|
|
11
|
+
block: Internal.eventBlock,
|
|
12
|
+
}
|
|
13
|
+
external fromPayload: payload => Internal.eventPayload = "%identity"
|
|
14
|
+
external toPayload: Internal.eventPayload => payload = "%identity"
|
|
15
|
+
|
|
1
16
|
let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
|
|
2
17
|
delete fields.hash
|
|
3
18
|
delete fields.number
|
|
4
19
|
delete fields.timestamp
|
|
5
20
|
}`)
|
|
6
21
|
|
|
7
|
-
let
|
|
22
|
+
let make = (~logger: Pino.t): Ecosystem.t => {
|
|
8
23
|
name: Evm,
|
|
9
24
|
blockFields: [
|
|
10
25
|
"number",
|
|
@@ -90,4 +105,28 @@ let ecosystem: Ecosystem.t = {
|
|
|
90
105
|
onEventBlockFilterSchema: S.object(s =>
|
|
91
106
|
s.field("block", S.option(S.object(s2 => s2.field("number", S.unknown))))
|
|
92
107
|
),
|
|
108
|
+
logger,
|
|
109
|
+
toEvent: eventItem => eventItem.payload->Internal.payloadToEvent,
|
|
110
|
+
toEventLogger: eventItem =>
|
|
111
|
+
Logging.createChildFrom(
|
|
112
|
+
~logger,
|
|
113
|
+
~params={
|
|
114
|
+
"contract": eventItem.eventConfig.contractName,
|
|
115
|
+
"event": eventItem.eventConfig.name,
|
|
116
|
+
"chainId": eventItem.chain->ChainMap.Chain.toChainId,
|
|
117
|
+
"block": eventItem.blockNumber,
|
|
118
|
+
"logIndex": eventItem.logIndex,
|
|
119
|
+
"address": (eventItem.payload->toPayload).srcAddress,
|
|
120
|
+
},
|
|
121
|
+
),
|
|
122
|
+
toRawEvent: eventItem => {
|
|
123
|
+
let payload = eventItem.payload->toPayload
|
|
124
|
+
eventItem->RawEvent.make(
|
|
125
|
+
~block=payload.block,
|
|
126
|
+
~transaction=payload.transaction,
|
|
127
|
+
~params=payload.params,
|
|
128
|
+
~srcAddress=payload.srcAddress,
|
|
129
|
+
~cleanUpRawEventFieldsInPlace,
|
|
130
|
+
)
|
|
131
|
+
},
|
|
93
132
|
}
|
package/src/sources/Evm.res.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Logging from "../Logging.res.mjs";
|
|
4
|
+
import * as RawEvent from "../RawEvent.res.mjs";
|
|
3
5
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
4
6
|
|
|
5
7
|
let cleanUpRawEventFieldsInPlace = (fields => {
|
|
@@ -8,91 +10,99 @@ let cleanUpRawEventFieldsInPlace = (fields => {
|
|
|
8
10
|
delete fields.timestamp
|
|
9
11
|
});
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
13
|
+
function make(logger) {
|
|
14
|
+
return {
|
|
15
|
+
name: "evm",
|
|
16
|
+
blockFields: [
|
|
17
|
+
"number",
|
|
18
|
+
"timestamp",
|
|
19
|
+
"hash",
|
|
20
|
+
"parentHash",
|
|
21
|
+
"nonce",
|
|
22
|
+
"sha3Uncles",
|
|
23
|
+
"logsBloom",
|
|
24
|
+
"transactionsRoot",
|
|
25
|
+
"stateRoot",
|
|
26
|
+
"receiptsRoot",
|
|
27
|
+
"miner",
|
|
28
|
+
"difficulty",
|
|
29
|
+
"totalDifficulty",
|
|
30
|
+
"extraData",
|
|
31
|
+
"size",
|
|
32
|
+
"gasLimit",
|
|
33
|
+
"gasUsed",
|
|
34
|
+
"uncles",
|
|
35
|
+
"baseFeePerGas",
|
|
36
|
+
"blobGasUsed",
|
|
37
|
+
"excessBlobGas",
|
|
38
|
+
"parentBeaconBlockRoot",
|
|
39
|
+
"withdrawalsRoot",
|
|
40
|
+
"l1BlockNumber",
|
|
41
|
+
"sendCount",
|
|
42
|
+
"sendRoot",
|
|
43
|
+
"mixHash"
|
|
44
|
+
],
|
|
45
|
+
transactionFields: [
|
|
46
|
+
"transactionIndex",
|
|
47
|
+
"hash",
|
|
48
|
+
"from",
|
|
49
|
+
"to",
|
|
50
|
+
"gas",
|
|
51
|
+
"gasPrice",
|
|
52
|
+
"maxPriorityFeePerGas",
|
|
53
|
+
"maxFeePerGas",
|
|
54
|
+
"cumulativeGasUsed",
|
|
55
|
+
"effectiveGasPrice",
|
|
56
|
+
"gasUsed",
|
|
57
|
+
"input",
|
|
58
|
+
"nonce",
|
|
59
|
+
"value",
|
|
60
|
+
"v",
|
|
61
|
+
"r",
|
|
62
|
+
"s",
|
|
63
|
+
"contractAddress",
|
|
64
|
+
"logsBloom",
|
|
65
|
+
"root",
|
|
66
|
+
"status",
|
|
67
|
+
"yParity",
|
|
68
|
+
"chainId",
|
|
69
|
+
"maxFeePerBlobGas",
|
|
70
|
+
"blobVersionedHashes",
|
|
71
|
+
"type",
|
|
72
|
+
"l1Fee",
|
|
73
|
+
"l1GasPrice",
|
|
74
|
+
"l1GasUsed",
|
|
75
|
+
"l1FeeScalar",
|
|
76
|
+
"gasUsedForL1",
|
|
77
|
+
"accessList",
|
|
78
|
+
"authorizationList"
|
|
79
|
+
],
|
|
80
|
+
blockNumberName: "number",
|
|
81
|
+
blockTimestampName: "timestamp",
|
|
82
|
+
blockHashName: "hash",
|
|
83
|
+
cleanUpRawEventFieldsInPlace: cleanUpRawEventFieldsInPlace,
|
|
84
|
+
onBlockMethodName: "onBlock",
|
|
85
|
+
onBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown))))),
|
|
86
|
+
onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown))))),
|
|
87
|
+
logger: logger,
|
|
88
|
+
toEvent: eventItem => eventItem.payload,
|
|
89
|
+
toEventLogger: eventItem => Logging.createChildFrom(logger, {
|
|
90
|
+
contract: eventItem.eventConfig.contractName,
|
|
91
|
+
event: eventItem.eventConfig.name,
|
|
92
|
+
chainId: eventItem.chain,
|
|
93
|
+
block: eventItem.blockNumber,
|
|
94
|
+
logIndex: eventItem.logIndex,
|
|
95
|
+
address: eventItem.payload.srcAddress
|
|
96
|
+
}),
|
|
97
|
+
toRawEvent: eventItem => {
|
|
98
|
+
let payload = eventItem.payload;
|
|
99
|
+
return RawEvent.make(eventItem, payload.block, payload.transaction, payload.params, payload.srcAddress, cleanUpRawEventFieldsInPlace);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
93
103
|
|
|
94
104
|
export {
|
|
95
105
|
cleanUpRawEventFieldsInPlace,
|
|
96
|
-
|
|
106
|
+
make,
|
|
97
107
|
}
|
|
98
|
-
/*
|
|
108
|
+
/* Logging Not a pure module */
|
package/src/sources/Fuel.res
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
+
// Fuel's concrete item payload. Erased to `Internal.eventPayload` on the item
|
|
2
|
+
// and recovered here via `toPayload`.
|
|
3
|
+
type payload = {
|
|
4
|
+
contractName: string,
|
|
5
|
+
eventName: string,
|
|
6
|
+
params: Internal.eventParams,
|
|
7
|
+
chainId: int,
|
|
8
|
+
srcAddress: Address.t,
|
|
9
|
+
logIndex: int,
|
|
10
|
+
transaction: Internal.eventTransaction,
|
|
11
|
+
block: Internal.eventBlock,
|
|
12
|
+
}
|
|
13
|
+
external fromPayload: payload => Internal.eventPayload = "%identity"
|
|
14
|
+
external toPayload: Internal.eventPayload => payload = "%identity"
|
|
15
|
+
|
|
1
16
|
let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
|
|
2
17
|
delete fields.id
|
|
3
18
|
delete fields.height
|
|
4
19
|
delete fields.time
|
|
5
20
|
}`)
|
|
6
21
|
|
|
7
|
-
let
|
|
22
|
+
let make = (~logger: Pino.t): Ecosystem.t => {
|
|
8
23
|
name: Fuel,
|
|
9
24
|
blockFields: ["id", "height", "time"],
|
|
10
25
|
transactionFields: ["id"],
|
|
@@ -25,4 +40,28 @@ let ecosystem: Ecosystem.t = {
|
|
|
25
40
|
onEventBlockFilterSchema: S.object(s =>
|
|
26
41
|
s.field("block", S.option(S.object(s2 => s2.field("height", S.unknown))))
|
|
27
42
|
),
|
|
43
|
+
logger,
|
|
44
|
+
toEvent: eventItem => eventItem.payload->Internal.payloadToEvent,
|
|
45
|
+
toEventLogger: eventItem =>
|
|
46
|
+
Logging.createChildFrom(
|
|
47
|
+
~logger,
|
|
48
|
+
~params={
|
|
49
|
+
"contract": eventItem.eventConfig.contractName,
|
|
50
|
+
"event": eventItem.eventConfig.name,
|
|
51
|
+
"chainId": eventItem.chain->ChainMap.Chain.toChainId,
|
|
52
|
+
"block": eventItem.blockNumber,
|
|
53
|
+
"logIndex": eventItem.logIndex,
|
|
54
|
+
"address": (eventItem.payload->toPayload).srcAddress,
|
|
55
|
+
},
|
|
56
|
+
),
|
|
57
|
+
toRawEvent: eventItem => {
|
|
58
|
+
let payload = eventItem.payload->toPayload
|
|
59
|
+
eventItem->RawEvent.make(
|
|
60
|
+
~block=payload.block,
|
|
61
|
+
~transaction=payload.transaction,
|
|
62
|
+
~params=payload.params,
|
|
63
|
+
~srcAddress=payload.srcAddress,
|
|
64
|
+
~cleanUpRawEventFieldsInPlace,
|
|
65
|
+
)
|
|
66
|
+
},
|
|
28
67
|
}
|
package/src/sources/Fuel.res.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Logging from "../Logging.res.mjs";
|
|
4
|
+
import * as RawEvent from "../RawEvent.res.mjs";
|
|
3
5
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
4
6
|
|
|
5
7
|
let cleanUpRawEventFieldsInPlace = (fields => {
|
|
@@ -8,33 +10,41 @@ let cleanUpRawEventFieldsInPlace = (fields => {
|
|
|
8
10
|
delete fields.time
|
|
9
11
|
});
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
13
|
+
function make(logger) {
|
|
14
|
+
return {
|
|
15
|
+
name: "fuel",
|
|
16
|
+
blockFields: [
|
|
17
|
+
"id",
|
|
18
|
+
"height",
|
|
19
|
+
"time"
|
|
20
|
+
],
|
|
21
|
+
transactionFields: ["id"],
|
|
22
|
+
blockNumberName: "height",
|
|
23
|
+
blockTimestampName: "time",
|
|
24
|
+
blockHashName: "id",
|
|
25
|
+
cleanUpRawEventFieldsInPlace: cleanUpRawEventFieldsInPlace,
|
|
26
|
+
onBlockMethodName: "onBlock",
|
|
27
|
+
onBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
|
|
28
|
+
onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
|
|
29
|
+
logger: logger,
|
|
30
|
+
toEvent: eventItem => eventItem.payload,
|
|
31
|
+
toEventLogger: eventItem => Logging.createChildFrom(logger, {
|
|
32
|
+
contract: eventItem.eventConfig.contractName,
|
|
33
|
+
event: eventItem.eventConfig.name,
|
|
34
|
+
chainId: eventItem.chain,
|
|
35
|
+
block: eventItem.blockNumber,
|
|
36
|
+
logIndex: eventItem.logIndex,
|
|
37
|
+
address: eventItem.payload.srcAddress
|
|
38
|
+
}),
|
|
39
|
+
toRawEvent: eventItem => {
|
|
40
|
+
let payload = eventItem.payload;
|
|
41
|
+
return RawEvent.make(eventItem, payload.block, payload.transaction, payload.params, payload.srcAddress, cleanUpRawEventFieldsInPlace);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
35
45
|
|
|
36
46
|
export {
|
|
37
47
|
cleanUpRawEventFieldsInPlace,
|
|
38
|
-
|
|
48
|
+
make,
|
|
39
49
|
}
|
|
40
|
-
/*
|
|
50
|
+
/* Logging Not a pure module */
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
//Manage clients in cache so we don't need to reinstantiate each time
|
|
2
|
-
//Ideally client should be passed in as a param to the functions but
|
|
3
|
-
//we are still sharing the same signature with eth archive query builder
|
|
4
|
-
|
|
5
|
-
module CachedClients = {
|
|
6
|
-
let cache: dict<HyperFuelClient.t> = Dict.make()
|
|
7
|
-
|
|
8
|
-
let getClient = url => {
|
|
9
|
-
switch cache->Utils.Dict.dangerouslyGetNonOption(url) {
|
|
10
|
-
| Some(client) => client
|
|
11
|
-
| None =>
|
|
12
|
-
let newClient = HyperFuelClient.make({url: url})
|
|
13
|
-
cache->Dict.set(url, newClient)
|
|
14
|
-
newClient
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
1
|
type hyperSyncPage<'item> = {
|
|
20
2
|
items: array<'item>,
|
|
21
3
|
nextBlock: int,
|
|
@@ -36,29 +18,8 @@ type item = {
|
|
|
36
18
|
block: block,
|
|
37
19
|
}
|
|
38
20
|
|
|
39
|
-
type blockNumberAndHash = {
|
|
40
|
-
blockNumber: int,
|
|
41
|
-
hash: string,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
21
|
type logsQueryPage = hyperSyncPage<item>
|
|
45
22
|
|
|
46
|
-
type missingParams = {
|
|
47
|
-
queryName: string,
|
|
48
|
-
missingParams: array<string>,
|
|
49
|
-
}
|
|
50
|
-
type queryError = UnexpectedMissingParams(missingParams)
|
|
51
|
-
|
|
52
|
-
let queryErrorToMsq = (e: queryError): string => {
|
|
53
|
-
switch e {
|
|
54
|
-
| UnexpectedMissingParams({queryName, missingParams}) =>
|
|
55
|
-
`${queryName} query failed due to unexpected missing params on response:
|
|
56
|
-
${missingParams->Array.joinUnsafe(", ")}`
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
type queryResponse<'a> = result<'a, queryError>
|
|
61
|
-
|
|
62
23
|
module GetLogs = {
|
|
63
24
|
type error =
|
|
64
25
|
| UnexpectedMissingParams({missingParams: array<string>})
|
|
@@ -66,6 +27,31 @@ module GetLogs = {
|
|
|
66
27
|
|
|
67
28
|
exception Error(error)
|
|
68
29
|
|
|
30
|
+
// Rust encodes structured failures as a JSON payload in the napi error's
|
|
31
|
+
// message: `{"kind":"MissingFields","fields":["receipt.txId", ...]}`.
|
|
32
|
+
// JSON.parse + shape check is the recovery protocol — no string-grepping
|
|
33
|
+
// on anyhow's Debug format.
|
|
34
|
+
let extractMissingParams = (exn: exn): option<array<string>> => {
|
|
35
|
+
let message = switch exn {
|
|
36
|
+
| JsExn(jsExn) => jsExn->JsExn.message
|
|
37
|
+
| _ => None
|
|
38
|
+
}
|
|
39
|
+
switch message {
|
|
40
|
+
| None => None
|
|
41
|
+
| Some(msg) =>
|
|
42
|
+
switch msg->JSON.parseOrThrow->JSON.Decode.object {
|
|
43
|
+
| exception _ => None
|
|
44
|
+
| None => None
|
|
45
|
+
| Some(obj) =>
|
|
46
|
+
switch (obj->Dict.get("kind"), obj->Dict.get("fields")) {
|
|
47
|
+
| (Some(String("MissingFields")), Some(Array(fields))) =>
|
|
48
|
+
Some(fields->Array.filterMap(JSON.Decode.string))
|
|
49
|
+
| _ => None
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
69
55
|
let makeRequestBody = (
|
|
70
56
|
~fromBlock,
|
|
71
57
|
~toBlockInclusive,
|
|
@@ -121,9 +107,7 @@ module GetLogs = {
|
|
|
121
107
|
let {receipts, blocks} = response_data
|
|
122
108
|
|
|
123
109
|
let blocksDict = Dict.make()
|
|
124
|
-
blocks
|
|
125
|
-
->(Utils.magic: option<'a> => 'a)
|
|
126
|
-
->Array.forEach(block => {
|
|
110
|
+
blocks->Array.forEach(block => {
|
|
127
111
|
blocksDict->Dict.set(block.height->(Utils.magic: int => string), block)
|
|
128
112
|
})
|
|
129
113
|
|
|
@@ -166,93 +150,30 @@ module GetLogs = {
|
|
|
166
150
|
page
|
|
167
151
|
}
|
|
168
152
|
|
|
169
|
-
let query = async (
|
|
153
|
+
let query = async (
|
|
154
|
+
~client: HyperFuelClient.t,
|
|
155
|
+
~fromBlock,
|
|
156
|
+
~toBlock,
|
|
157
|
+
~recieptsSelection,
|
|
158
|
+
): logsQueryPage => {
|
|
170
159
|
let query: HyperFuelClient.QueryTypes.query = makeRequestBody(
|
|
171
160
|
~fromBlock,
|
|
172
161
|
~toBlockInclusive=toBlock,
|
|
173
162
|
~recieptsSelection,
|
|
174
163
|
)
|
|
175
164
|
|
|
176
|
-
let
|
|
177
|
-
|
|
178
|
-
|
|
165
|
+
let res = switch await client->HyperFuelClient.getSelectedData(query) {
|
|
166
|
+
| res => res
|
|
167
|
+
| exception exn =>
|
|
168
|
+
switch exn->extractMissingParams {
|
|
169
|
+
| Some(missingParams) => throw(Error(UnexpectedMissingParams({missingParams: missingParams})))
|
|
170
|
+
| None => throw(exn)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
179
173
|
if res.nextBlock <= fromBlock {
|
|
180
|
-
// Might happen when /height response was from another instance of
|
|
174
|
+
// Might happen when /height response was from another instance of HyperFuel
|
|
181
175
|
throw(Error(WrongInstance))
|
|
182
176
|
}
|
|
183
177
|
res->convertResponse
|
|
184
178
|
}
|
|
185
179
|
}
|
|
186
|
-
|
|
187
|
-
module BlockData = {
|
|
188
|
-
let convertResponse = (res: HyperFuelClient.queryResponseTyped): option<
|
|
189
|
-
ReorgDetection.blockDataWithTimestamp,
|
|
190
|
-
> => {
|
|
191
|
-
res.data.blocks->Option.flatMap(blocks => {
|
|
192
|
-
blocks
|
|
193
|
-
->Array.get(0)
|
|
194
|
-
->Option.map(block => {
|
|
195
|
-
switch block {
|
|
196
|
-
| {height: blockNumber, time: timestamp, id: blockHash} =>
|
|
197
|
-
(
|
|
198
|
-
{
|
|
199
|
-
blockTimestamp: timestamp,
|
|
200
|
-
blockNumber,
|
|
201
|
-
blockHash,
|
|
202
|
-
}: ReorgDetection.blockDataWithTimestamp
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
})
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
let rec queryBlockData = async (~serverUrl, ~blockNumber, ~logger): option<
|
|
210
|
-
ReorgDetection.blockDataWithTimestamp,
|
|
211
|
-
> => {
|
|
212
|
-
let query: HyperFuelClient.QueryTypes.query = {
|
|
213
|
-
fromBlock: blockNumber,
|
|
214
|
-
toBlockExclusive: blockNumber + 1,
|
|
215
|
-
// FIXME: Theoretically it should work without the outputs filter, but it doesn't for some reason
|
|
216
|
-
outputs: [%raw(`{}`)],
|
|
217
|
-
// FIXME: Had to add inputs {} as well, since it failed on block 1211599 during wildcard Call indexing
|
|
218
|
-
inputs: [%raw(`{}`)],
|
|
219
|
-
fieldSelection: {
|
|
220
|
-
block: [Height, Id, Time],
|
|
221
|
-
},
|
|
222
|
-
includeAllBlocks: true,
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
let hyperFuelClient = CachedClients.getClient(serverUrl)
|
|
226
|
-
|
|
227
|
-
let logger = Logging.createChildFrom(
|
|
228
|
-
~logger,
|
|
229
|
-
~params={"logType": "hypersync get blockhash query", "blockNumber": blockNumber},
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
let executeQuery = () => hyperFuelClient->HyperFuelClient.getSelectedData(query)
|
|
233
|
-
|
|
234
|
-
let res = await executeQuery->Time.retryAsyncWithExponentialBackOff(~logger)
|
|
235
|
-
|
|
236
|
-
// If the block is not found, retry the query. This can occur since replicas of hypersync might not hack caught up yet
|
|
237
|
-
if res.nextBlock <= blockNumber {
|
|
238
|
-
let logger = Logging.createChild(~params={"url": serverUrl})
|
|
239
|
-
let delayMilliseconds = 100
|
|
240
|
-
logger->Logging.childInfo(
|
|
241
|
-
`Block #${blockNumber->Int.toString} not found in HyperFuel. HyperFuel has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in ${delayMilliseconds->Int.toString}ms.`,
|
|
242
|
-
)
|
|
243
|
-
await Time.resolvePromiseAfterDelay(~delayMilliseconds)
|
|
244
|
-
await queryBlockData(~serverUrl, ~blockNumber, ~logger)
|
|
245
|
-
} else {
|
|
246
|
-
res->convertResponse
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
let queryBlockData = BlockData.queryBlockData
|
|
252
|
-
|
|
253
|
-
let heightRoute = Rest.route(() => {
|
|
254
|
-
path: "/height",
|
|
255
|
-
method: Get,
|
|
256
|
-
input: _ => (),
|
|
257
|
-
responses: [s => s.field("height", S.int)],
|
|
258
|
-
})
|