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.
- package/index.d.ts +23 -5
- package/package.json +6 -6
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/ChainFetching.res +21 -10
- package/src/ChainFetching.res.mjs +11 -10
- package/src/ChainState.res +401 -171
- package/src/ChainState.res.mjs +270 -104
- package/src/ChainState.resi +19 -7
- package/src/Config.res +11 -27
- package/src/Config.res.mjs +8 -7
- package/src/Core.res +7 -0
- package/src/CrossChainState.res +82 -82
- package/src/CrossChainState.res.mjs +52 -59
- package/src/CrossChainState.resi +1 -1
- package/src/Ecosystem.res +3 -3
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Envio.res +14 -9
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +117 -69
- package/src/EventConfigBuilder.res.mjs +71 -34
- package/src/EventProcessing.res +19 -15
- package/src/EventProcessing.res.mjs +13 -12
- package/src/FetchState.res +410 -185
- package/src/FetchState.res.mjs +268 -253
- package/src/HandlerLoader.res +8 -113
- package/src/HandlerLoader.res.mjs +2 -88
- package/src/HandlerRegister.res +518 -144
- package/src/HandlerRegister.res.mjs +285 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerState.res +6 -3
- package/src/IndexerState.res.mjs +3 -3
- package/src/IndexerState.resi +1 -1
- package/src/IndexingAddresses.res +10 -7
- package/src/IndexingAddresses.res.mjs +8 -7
- package/src/IndexingAddresses.resi +3 -1
- package/src/Internal.res +104 -39
- package/src/Internal.res.mjs +11 -1
- package/src/LogSelection.res +102 -165
- package/src/LogSelection.res.mjs +101 -116
- package/src/Main.res +49 -164
- package/src/Main.res.mjs +39 -104
- package/src/Metrics.res +43 -2
- package/src/Metrics.res.mjs +39 -3
- package/src/Prometheus.res +0 -35
- package/src/Prometheus.res.mjs +33 -68
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateItems.res +20 -7
- package/src/SimulateItems.res.mjs +7 -11
- package/src/TestIndexer.res +1 -1
- package/src/TestIndexer.res.mjs +1 -1
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +19 -12
- package/src/sources/EventRouter.res.mjs +7 -5
- package/src/sources/Evm.res +58 -5
- package/src/sources/Evm.res.mjs +44 -5
- package/src/sources/EvmChain.res +14 -18
- package/src/sources/EvmChain.res.mjs +12 -13
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +8 -3
- package/src/sources/Fuel.res.mjs +5 -4
- package/src/sources/HyperFuelSource.res +31 -40
- package/src/sources/HyperFuelSource.res.mjs +52 -44
- package/src/sources/HyperSync.res +31 -9
- package/src/sources/HyperSync.res.mjs +47 -31
- package/src/sources/HyperSync.resi +10 -3
- package/src/sources/HyperSyncClient.res +15 -4
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +58 -90
- package/src/sources/HyperSyncSource.res.mjs +57 -66
- package/src/sources/RpcSource.res +118 -120
- package/src/sources/RpcSource.res.mjs +92 -74
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +5 -3
- package/src/sources/SimulateSource.res.mjs +12 -4
- package/src/sources/Source.res +19 -5
- package/src/sources/SourceManager.res +60 -10
- package/src/sources/SourceManager.res.mjs +54 -8
- package/src/sources/SourceManager.resi +10 -0
- package/src/sources/Svm.res +14 -10
- package/src/sources/Svm.res.mjs +23 -6
- package/src/sources/SvmHyperSyncClient.res +5 -6
- package/src/sources/SvmHyperSyncSource.res +82 -41
- package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
- package/src/sources/TransactionStore.res +6 -107
- package/src/sources/TransactionStore.res.mjs +5 -86
- package/svm.schema.json +19 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Core from "../Core.res.mjs";
|
|
4
|
+
import * as FieldMask from "./FieldMask.res.mjs";
|
|
5
|
+
|
|
6
|
+
function make(ecosystem, shouldChecksum) {
|
|
7
|
+
let ctor = Core.getAddon().BlockStore;
|
|
8
|
+
switch (ecosystem) {
|
|
9
|
+
case "evm" :
|
|
10
|
+
return ctor.newEvm(shouldChecksum);
|
|
11
|
+
case "fuel" :
|
|
12
|
+
return ctor.newFuel();
|
|
13
|
+
case "svm" :
|
|
14
|
+
return ctor.newSvm();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let makeMaskFn = FieldMask.makeMaskFn;
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
make,
|
|
22
|
+
makeMaskFn,
|
|
23
|
+
}
|
|
24
|
+
/* Core Not a pure module */
|
|
@@ -96,16 +96,16 @@ let getEvmEventId = (~sighash, ~topicCount) => {
|
|
|
96
96
|
sighash ++ "_" ++ topicCount->Int.toString
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
let fromEvmEventModsOrThrow = (events: array<Internal.
|
|
100
|
-
Internal.
|
|
99
|
+
let fromEvmEventModsOrThrow = (events: array<Internal.evmOnEventRegistration>, ~chain): t<
|
|
100
|
+
Internal.evmOnEventRegistration,
|
|
101
101
|
> => {
|
|
102
102
|
let router = empty()
|
|
103
103
|
events->Array.forEach(config => {
|
|
104
104
|
router->addOrThrow(
|
|
105
|
-
config.id,
|
|
105
|
+
config.eventConfig.id,
|
|
106
106
|
config,
|
|
107
|
-
~contractName=config.contractName,
|
|
108
|
-
~eventName=config.name,
|
|
107
|
+
~contractName=config.eventConfig.contractName,
|
|
108
|
+
~eventName=config.eventConfig.name,
|
|
109
109
|
~chain,
|
|
110
110
|
~isWildcard=config.isWildcard,
|
|
111
111
|
)
|
|
@@ -131,21 +131,26 @@ type svmProgramOrdering = {
|
|
|
131
131
|
byteLengthsDesc: array<int>,
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
let fromSvmEventConfigsOrThrow = (events: array<Internal.
|
|
135
|
-
t<Internal.
|
|
134
|
+
let fromSvmEventConfigsOrThrow = (events: array<Internal.svmOnEventRegistration>, ~chain): (
|
|
135
|
+
t<Internal.svmOnEventRegistration>,
|
|
136
136
|
array<svmProgramOrdering>,
|
|
137
137
|
) => {
|
|
138
138
|
let router = empty()
|
|
139
139
|
events->Array.forEach(config => {
|
|
140
|
+
let eventConfig =
|
|
141
|
+
config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
140
142
|
// The router tag must include the programId so two programs declaring the
|
|
141
143
|
// same discriminator coexist. The source-side lookup uses the same shape
|
|
142
144
|
// via `getSvmEventId(~programId, ~discriminator)`.
|
|
143
|
-
let routerTag = getSvmEventId(
|
|
145
|
+
let routerTag = getSvmEventId(
|
|
146
|
+
~programId=eventConfig.programId,
|
|
147
|
+
~discriminator=eventConfig.discriminator,
|
|
148
|
+
)
|
|
144
149
|
router->addOrThrow(
|
|
145
150
|
routerTag,
|
|
146
151
|
config,
|
|
147
|
-
~contractName=
|
|
148
|
-
~eventName=
|
|
152
|
+
~contractName=eventConfig.contractName,
|
|
153
|
+
~eventName=eventConfig.name,
|
|
149
154
|
~chain,
|
|
150
155
|
~isWildcard=config.isWildcard,
|
|
151
156
|
)
|
|
@@ -154,7 +159,9 @@ let fromSvmEventConfigsOrThrow = (events: array<Internal.svmInstructionEventConf
|
|
|
154
159
|
// Per-program list of declared discriminator byte lengths, sorted desc.
|
|
155
160
|
let byProgram: dict<Utils.Set.t<int>> = Dict.make()
|
|
156
161
|
events->Array.forEach(config => {
|
|
157
|
-
let
|
|
162
|
+
let eventConfig =
|
|
163
|
+
config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
164
|
+
let key = eventConfig.programId->SvmTypes.Pubkey.toString
|
|
158
165
|
let set = switch byProgram->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
159
166
|
| Some(s) => s
|
|
160
167
|
| None =>
|
|
@@ -162,7 +169,7 @@ let fromSvmEventConfigsOrThrow = (events: array<Internal.svmInstructionEventConf
|
|
|
162
169
|
byProgram->Dict.set(key, s)
|
|
163
170
|
s
|
|
164
171
|
}
|
|
165
|
-
let _ = set->Utils.Set.add(
|
|
172
|
+
let _ = set->Utils.Set.add(eventConfig.discriminatorByteLen)
|
|
166
173
|
})
|
|
167
174
|
let ordering =
|
|
168
175
|
byProgram
|
|
@@ -103,7 +103,7 @@ function getEvmEventId(sighash, topicCount) {
|
|
|
103
103
|
|
|
104
104
|
function fromEvmEventModsOrThrow(events, chain) {
|
|
105
105
|
let router = {};
|
|
106
|
-
events.forEach(config => addOrThrow$1(router, config.id, config, config.contractName, config.isWildcard, config.name, chain));
|
|
106
|
+
events.forEach(config => addOrThrow$1(router, config.eventConfig.id, config, config.eventConfig.contractName, config.isWildcard, config.eventConfig.name, chain));
|
|
107
107
|
return router;
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -118,12 +118,14 @@ function getSvmEventId(programId, discriminator) {
|
|
|
118
118
|
function fromSvmEventConfigsOrThrow(events, chain) {
|
|
119
119
|
let router = {};
|
|
120
120
|
events.forEach(config => {
|
|
121
|
-
let
|
|
122
|
-
|
|
121
|
+
let eventConfig = config.eventConfig;
|
|
122
|
+
let routerTag = getSvmEventId(eventConfig.programId, eventConfig.discriminator);
|
|
123
|
+
addOrThrow$1(router, routerTag, config, eventConfig.contractName, config.isWildcard, eventConfig.name, chain);
|
|
123
124
|
});
|
|
124
125
|
let byProgram = {};
|
|
125
126
|
events.forEach(config => {
|
|
126
|
-
let
|
|
127
|
+
let eventConfig = config.eventConfig;
|
|
128
|
+
let key = eventConfig.programId;
|
|
127
129
|
let s = byProgram[key];
|
|
128
130
|
let set;
|
|
129
131
|
if (s !== undefined) {
|
|
@@ -133,7 +135,7 @@ function fromSvmEventConfigsOrThrow(events, chain) {
|
|
|
133
135
|
byProgram[key] = s$1;
|
|
134
136
|
set = s$1;
|
|
135
137
|
}
|
|
136
|
-
set.add(
|
|
138
|
+
set.add(eventConfig.discriminatorByteLen);
|
|
137
139
|
});
|
|
138
140
|
let ordering = Object.entries(byProgram).map(param => {
|
|
139
141
|
let sorted = Array.from(param[1]).toSorted((a, b) => b - a | 0);
|
package/src/sources/Evm.res
CHANGED
|
@@ -10,7 +10,9 @@ type payload = {
|
|
|
10
10
|
srcAddress: Address.t,
|
|
11
11
|
logIndex: int,
|
|
12
12
|
transaction?: Internal.eventTransaction,
|
|
13
|
-
block
|
|
13
|
+
// HyperSync omits `block` (it lives raw in the per-chain store and is written
|
|
14
|
+
// onto the payload at batch prep); RPC/simulate build it inline.
|
|
15
|
+
block?: Internal.eventBlock,
|
|
14
16
|
}
|
|
15
17
|
external fromPayload: payload => Internal.eventPayload = "%identity"
|
|
16
18
|
external toPayload: Internal.eventPayload => payload = "%identity"
|
|
@@ -27,6 +29,42 @@ let transactionFields =
|
|
|
27
29
|
// per event at config build and cached on the event config.
|
|
28
30
|
let eventTransactionFieldMask = TransactionStore.makeMaskFn(transactionFields)
|
|
29
31
|
|
|
32
|
+
// Ordered block field names. The index of each is the field code shared with the
|
|
33
|
+
// Rust store (`EvmBlockField`) — keep this order in sync.
|
|
34
|
+
let blockFields = [
|
|
35
|
+
"number",
|
|
36
|
+
"timestamp",
|
|
37
|
+
"hash",
|
|
38
|
+
"parentHash",
|
|
39
|
+
"nonce",
|
|
40
|
+
"sha3Uncles",
|
|
41
|
+
"logsBloom",
|
|
42
|
+
"transactionsRoot",
|
|
43
|
+
"stateRoot",
|
|
44
|
+
"receiptsRoot",
|
|
45
|
+
"miner",
|
|
46
|
+
"difficulty",
|
|
47
|
+
"totalDifficulty",
|
|
48
|
+
"extraData",
|
|
49
|
+
"size",
|
|
50
|
+
"gasLimit",
|
|
51
|
+
"gasUsed",
|
|
52
|
+
"uncles",
|
|
53
|
+
"baseFeePerGas",
|
|
54
|
+
"blobGasUsed",
|
|
55
|
+
"excessBlobGas",
|
|
56
|
+
"parentBeaconBlockRoot",
|
|
57
|
+
"withdrawalsRoot",
|
|
58
|
+
"l1BlockNumber",
|
|
59
|
+
"sendCount",
|
|
60
|
+
"sendRoot",
|
|
61
|
+
"mixHash",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
// One event's selected block fields → store selection bitmask. Computed per
|
|
65
|
+
// event at config build and cached on the event config.
|
|
66
|
+
let eventBlockFieldMask = BlockStore.makeMaskFn(blockFields)
|
|
67
|
+
|
|
30
68
|
let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
|
|
31
69
|
delete fields.hash
|
|
32
70
|
delete fields.number
|
|
@@ -52,8 +90,11 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
52
90
|
// range chunk is validated by `eventBlockRangeSchema` in
|
|
53
91
|
// `LogSelection.res` which rejects `_lte`/`_every` (use `onBlock` for
|
|
54
92
|
// stride- and endBlock-based block handlers).
|
|
93
|
+
// `S.strict` on the inner object rejects unknown `block` fields (e.g. a
|
|
94
|
+
// `numbre` typo or `block: {timestamp: ...}`) instead of silently
|
|
95
|
+
// ignoring them.
|
|
55
96
|
onEventBlockFilterSchema: S.object(s =>
|
|
56
|
-
s.field("block", S.option(S.object(s2 => s2.field("number", S.unknown))))
|
|
97
|
+
s.field("block", S.option(S.object(s2 => s2.field("number", S.unknown))->S.strict))
|
|
57
98
|
),
|
|
58
99
|
logger,
|
|
59
100
|
// The payload carries `transaction` by batch prep (HyperSync) or inline
|
|
@@ -63,8 +104,8 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
63
104
|
Logging.createChildFrom(
|
|
64
105
|
~logger,
|
|
65
106
|
~params={
|
|
66
|
-
"contract": eventItem.eventConfig.contractName,
|
|
67
|
-
"event": eventItem.eventConfig.name,
|
|
107
|
+
"contract": eventItem.onEventRegistration.eventConfig.contractName,
|
|
108
|
+
"event": eventItem.onEventRegistration.eventConfig.name,
|
|
68
109
|
"chainId": eventItem.chain->ChainMap.Chain.toChainId,
|
|
69
110
|
"block": eventItem.blockNumber,
|
|
70
111
|
"logIndex": eventItem.logIndex,
|
|
@@ -74,7 +115,17 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
74
115
|
toRawEvent: eventItem => {
|
|
75
116
|
let payload = eventItem.payload->toPayload
|
|
76
117
|
let eventConfig =
|
|
77
|
-
eventItem.eventConfig->(
|
|
118
|
+
eventItem.onEventRegistration.eventConfig->(
|
|
119
|
+
Utils.magic: Internal.eventConfig => Internal.evmEventConfig
|
|
120
|
+
)
|
|
121
|
+
// Store-backed payloads get `block` written at batch prep and inline
|
|
122
|
+
// sources carry it from the start, with hash/timestamp always selected —
|
|
123
|
+
// so both are present by the time a raw event is built.
|
|
124
|
+
let header = switch payload.block {
|
|
125
|
+
| Some(block) => block->(Utils.magic: Internal.eventBlock => {"hash": string, "timestamp": int})
|
|
126
|
+
| None =>
|
|
127
|
+
JsError.throwWithMessage("Unexpected case: The event block is missing for a raw event")
|
|
128
|
+
}
|
|
78
129
|
eventItem->RawEvent.make(
|
|
79
130
|
~block=payload.block,
|
|
80
131
|
~transaction=payload.transaction,
|
|
@@ -84,6 +135,8 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
84
135
|
? ()->(Utils.magic: unit => Internal.eventParams)
|
|
85
136
|
: payload.params,
|
|
86
137
|
~srcAddress=payload.srcAddress,
|
|
138
|
+
~blockHash=header["hash"],
|
|
139
|
+
~blockTimestamp=header["timestamp"],
|
|
87
140
|
~cleanUpRawEventFieldsInPlace,
|
|
88
141
|
)
|
|
89
142
|
},
|
package/src/sources/Evm.res.mjs
CHANGED
|
@@ -3,11 +3,46 @@
|
|
|
3
3
|
import * as Logging from "../Logging.res.mjs";
|
|
4
4
|
import * as Internal from "../Internal.res.mjs";
|
|
5
5
|
import * as RawEvent from "../RawEvent.res.mjs";
|
|
6
|
+
import * as BlockStore from "./BlockStore.res.mjs";
|
|
7
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
6
9
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
7
10
|
import * as TransactionStore from "./TransactionStore.res.mjs";
|
|
8
11
|
|
|
9
12
|
let eventTransactionFieldMask = TransactionStore.makeMaskFn(Internal.allEvmTransactionFields);
|
|
10
13
|
|
|
14
|
+
let blockFields = [
|
|
15
|
+
"number",
|
|
16
|
+
"timestamp",
|
|
17
|
+
"hash",
|
|
18
|
+
"parentHash",
|
|
19
|
+
"nonce",
|
|
20
|
+
"sha3Uncles",
|
|
21
|
+
"logsBloom",
|
|
22
|
+
"transactionsRoot",
|
|
23
|
+
"stateRoot",
|
|
24
|
+
"receiptsRoot",
|
|
25
|
+
"miner",
|
|
26
|
+
"difficulty",
|
|
27
|
+
"totalDifficulty",
|
|
28
|
+
"extraData",
|
|
29
|
+
"size",
|
|
30
|
+
"gasLimit",
|
|
31
|
+
"gasUsed",
|
|
32
|
+
"uncles",
|
|
33
|
+
"baseFeePerGas",
|
|
34
|
+
"blobGasUsed",
|
|
35
|
+
"excessBlobGas",
|
|
36
|
+
"parentBeaconBlockRoot",
|
|
37
|
+
"withdrawalsRoot",
|
|
38
|
+
"l1BlockNumber",
|
|
39
|
+
"sendCount",
|
|
40
|
+
"sendRoot",
|
|
41
|
+
"mixHash"
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
let eventBlockFieldMask = BlockStore.makeMaskFn(blockFields);
|
|
45
|
+
|
|
11
46
|
let cleanUpRawEventFieldsInPlace = (fields => {
|
|
12
47
|
delete fields.hash
|
|
13
48
|
delete fields.number
|
|
@@ -23,12 +58,12 @@ function make(logger) {
|
|
|
23
58
|
cleanUpRawEventFieldsInPlace: cleanUpRawEventFieldsInPlace,
|
|
24
59
|
onBlockMethodName: "onBlock",
|
|
25
60
|
onBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown))))),
|
|
26
|
-
onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown))))),
|
|
61
|
+
onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.strict(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown)))))),
|
|
27
62
|
logger: logger,
|
|
28
63
|
toEvent: eventItem => eventItem.payload,
|
|
29
64
|
toEventLogger: eventItem => Logging.createChildFrom(logger, {
|
|
30
|
-
contract: eventItem.eventConfig.contractName,
|
|
31
|
-
event: eventItem.eventConfig.name,
|
|
65
|
+
contract: eventItem.onEventRegistration.eventConfig.contractName,
|
|
66
|
+
event: eventItem.onEventRegistration.eventConfig.name,
|
|
32
67
|
chainId: eventItem.chain,
|
|
33
68
|
block: eventItem.blockNumber,
|
|
34
69
|
logIndex: eventItem.logIndex,
|
|
@@ -36,8 +71,10 @@ function make(logger) {
|
|
|
36
71
|
}),
|
|
37
72
|
toRawEvent: eventItem => {
|
|
38
73
|
let payload = eventItem.payload;
|
|
39
|
-
let eventConfig = eventItem.eventConfig;
|
|
40
|
-
|
|
74
|
+
let eventConfig = eventItem.onEventRegistration.eventConfig;
|
|
75
|
+
let block = payload.block;
|
|
76
|
+
let header = block !== undefined ? Primitive_option.valFromOption(block) : Stdlib_JsError.throwWithMessage("Unexpected case: The event block is missing for a raw event");
|
|
77
|
+
return RawEvent.make(eventItem, payload.block, payload.transaction, eventConfig.paramsMetadata.length === 0 ? undefined : payload.params, payload.srcAddress, header.hash, header.timestamp, cleanUpRawEventFieldsInPlace);
|
|
41
78
|
}
|
|
42
79
|
};
|
|
43
80
|
}
|
|
@@ -47,6 +84,8 @@ let transactionFields = Internal.allEvmTransactionFields;
|
|
|
47
84
|
export {
|
|
48
85
|
transactionFields,
|
|
49
86
|
eventTransactionFieldMask,
|
|
87
|
+
blockFields,
|
|
88
|
+
eventBlockFieldMask,
|
|
50
89
|
cleanUpRawEventFieldsInPlace,
|
|
51
90
|
make,
|
|
52
91
|
}
|
package/src/sources/EvmChain.res
CHANGED
|
@@ -39,39 +39,35 @@ let getSyncConfig = (
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
let collectEventParams = (
|
|
42
|
+
let collectEventParams = (onEventRegistrations: array<Internal.evmOnEventRegistration>): array<
|
|
43
43
|
HyperSyncClient.Decoder.eventParamsInput,
|
|
44
44
|
> => {
|
|
45
45
|
let result = []
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
})
|
|
56
|
-
->ignore
|
|
46
|
+
onEventRegistrations->Array.forEach(reg => {
|
|
47
|
+
let event = reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.evmEventConfig)
|
|
48
|
+
result
|
|
49
|
+
->Array.push({
|
|
50
|
+
HyperSyncClient.Decoder.sighash: event.sighash,
|
|
51
|
+
topicCount: event.topicCount,
|
|
52
|
+
eventName: event.name,
|
|
53
|
+
contractName: event.contractName,
|
|
54
|
+
params: event.paramsMetadata,
|
|
57
55
|
})
|
|
56
|
+
->ignore
|
|
58
57
|
})
|
|
59
58
|
result
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
let makeSources = (
|
|
63
62
|
~chain,
|
|
64
|
-
~
|
|
63
|
+
~onEventRegistrations: array<Internal.evmOnEventRegistration>,
|
|
65
64
|
~hyperSync,
|
|
66
65
|
~rpcs: array<rpc>,
|
|
67
66
|
~lowercaseAddresses,
|
|
68
67
|
) => {
|
|
69
|
-
let eventRouter =
|
|
70
|
-
contracts
|
|
71
|
-
->Array.flatMap(contract => contract.events)
|
|
72
|
-
->EventRouter.fromEvmEventModsOrThrow(~chain)
|
|
68
|
+
let eventRouter = onEventRegistrations->EventRouter.fromEvmEventModsOrThrow(~chain)
|
|
73
69
|
|
|
74
|
-
let allEventParams = collectEventParams(
|
|
70
|
+
let allEventParams = collectEventParams(onEventRegistrations)
|
|
75
71
|
|
|
76
72
|
let sources = switch hyperSync {
|
|
77
73
|
| Some(endpointUrl) => [
|
|
@@ -20,25 +20,24 @@ function getSyncConfig(param) {
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function collectEventParams(
|
|
23
|
+
function collectEventParams(onEventRegistrations) {
|
|
24
24
|
let result = [];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
25
|
+
onEventRegistrations.forEach(reg => {
|
|
26
|
+
let event = reg.eventConfig;
|
|
27
|
+
result.push({
|
|
28
|
+
sighash: event.sighash,
|
|
29
|
+
topicCount: event.topicCount,
|
|
30
|
+
eventName: event.name,
|
|
31
|
+
contractName: event.contractName,
|
|
32
|
+
params: event.paramsMetadata
|
|
34
33
|
});
|
|
35
34
|
});
|
|
36
35
|
return result;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
function makeSources(chain,
|
|
40
|
-
let eventRouter = EventRouter.fromEvmEventModsOrThrow(
|
|
41
|
-
let allEventParams = collectEventParams(
|
|
38
|
+
function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddresses) {
|
|
39
|
+
let eventRouter = EventRouter.fromEvmEventModsOrThrow(onEventRegistrations, chain);
|
|
40
|
+
let allEventParams = collectEventParams(onEventRegistrations);
|
|
42
41
|
let sources = hyperSync !== undefined ? [HyperSyncSource.make({
|
|
43
42
|
chain: chain,
|
|
44
43
|
endpointUrl: hyperSync,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Selection-bitmask helpers shared by the per-chain field stores
|
|
2
|
+
// (`TransactionStore`, `BlockStore`). A field's bit index is its position in the
|
|
3
|
+
// ecosystem's ordered field-name array — the same code the Rust store uses.
|
|
4
|
+
|
|
5
|
+
// Field-name → bit-index map from an ordered field-name array.
|
|
6
|
+
let fieldCodes = (fields: array<string>): dict<int> => {
|
|
7
|
+
let codes = Dict.make()
|
|
8
|
+
fields->Array.forEachWithIndex((name, i) => codes->Dict.set(name, i))
|
|
9
|
+
codes
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let pow2: int => float = %raw(`c => Math.pow(2, c)`)
|
|
13
|
+
|
|
14
|
+
// One event's selected fields as a bitmask float (bit `code` set ⇔ selected).
|
|
15
|
+
// Each field appears once, so summing `pow2(code)` sets distinct bits with no
|
|
16
|
+
// overlap; the result stays exact in f64 (codes span 0..31, so a mask is at most
|
|
17
|
+
// 2^32-1).
|
|
18
|
+
let maskFromFields = (selectedFields: Utils.Set.t<string>, ~codes: dict<int>): float => {
|
|
19
|
+
let mask = ref(0.)
|
|
20
|
+
selectedFields->Utils.Set.forEach(name =>
|
|
21
|
+
switch codes->Utils.Dict.dangerouslyGetNonOption(name) {
|
|
22
|
+
| Some(code) => mask := mask.contents +. pow2(code)
|
|
23
|
+
| None => ()
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
mask.contents
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Build an ecosystem's per-event mask function from its ordered field-name
|
|
30
|
+
// array. The field codes are derived once and closed over.
|
|
31
|
+
let makeMaskFn = (fields: array<string>): (Utils.Set.t<string> => float) => {
|
|
32
|
+
let codes = fieldCodes(fields)
|
|
33
|
+
selectedFields => selectedFields->maskFromFields(~codes)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Bitwise OR of two per-event masks. Masks fit in 32 bits (≤32 fields), so
|
|
37
|
+
// `>>> 0` recovers the unsigned value that a plain `|` renders negative once bit
|
|
38
|
+
// 31 is set.
|
|
39
|
+
let orMask: (float, float) => float = %raw(`(a, b) => (a | b) >>> 0`)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function fieldCodes(fields) {
|
|
5
|
+
let codes = {};
|
|
6
|
+
fields.forEach((name, i) => {
|
|
7
|
+
codes[name] = i;
|
|
8
|
+
});
|
|
9
|
+
return codes;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let pow2 = (c => Math.pow(2, c));
|
|
13
|
+
|
|
14
|
+
function maskFromFields(selectedFields, codes) {
|
|
15
|
+
let mask = {
|
|
16
|
+
contents: 0
|
|
17
|
+
};
|
|
18
|
+
selectedFields.forEach(name => {
|
|
19
|
+
let code = codes[name];
|
|
20
|
+
if (code !== undefined) {
|
|
21
|
+
mask.contents = mask.contents + pow2(code);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return mask.contents;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function makeMaskFn(fields) {
|
|
29
|
+
let codes = fieldCodes(fields);
|
|
30
|
+
return selectedFields => maskFromFields(selectedFields, codes);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let orMask = ((a, b) => (a | b) >>> 0);
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
fieldCodes,
|
|
37
|
+
pow2,
|
|
38
|
+
maskFromFields,
|
|
39
|
+
makeMaskFn,
|
|
40
|
+
orMask,
|
|
41
|
+
}
|
|
42
|
+
/* No side effect */
|
package/src/sources/Fuel.res
CHANGED
|
@@ -35,8 +35,10 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
35
35
|
// Analogous to EVM, but keyed by `block.height` instead of
|
|
36
36
|
// `block.number`. See `Evm.res` for the rationale on the two-stage
|
|
37
37
|
// parse and the `_lte`/`_every` rejection.
|
|
38
|
+
// `S.strict` on the inner object rejects unknown `block` fields — including
|
|
39
|
+
// `block.number`, which is EVM-only; Fuel filters by `block.height`.
|
|
38
40
|
onEventBlockFilterSchema: S.object(s =>
|
|
39
|
-
s.field("block", S.option(S.object(s2 => s2.field("height", S.unknown))))
|
|
41
|
+
s.field("block", S.option(S.object(s2 => s2.field("height", S.unknown))->S.strict))
|
|
40
42
|
),
|
|
41
43
|
logger,
|
|
42
44
|
toEvent: eventItem => eventItem.payload->(Utils.magic: Internal.eventPayload => Internal.event),
|
|
@@ -44,8 +46,8 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
44
46
|
Logging.createChildFrom(
|
|
45
47
|
~logger,
|
|
46
48
|
~params={
|
|
47
|
-
"contract": eventItem.eventConfig.contractName,
|
|
48
|
-
"event": eventItem.eventConfig.name,
|
|
49
|
+
"contract": eventItem.onEventRegistration.eventConfig.contractName,
|
|
50
|
+
"event": eventItem.onEventRegistration.eventConfig.name,
|
|
49
51
|
"chainId": eventItem.chain->ChainMap.Chain.toChainId,
|
|
50
52
|
"block": eventItem.blockNumber,
|
|
51
53
|
"logIndex": eventItem.logIndex,
|
|
@@ -54,11 +56,14 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
54
56
|
),
|
|
55
57
|
toRawEvent: eventItem => {
|
|
56
58
|
let payload = eventItem.payload->toPayload
|
|
59
|
+
let header = payload.block->(Utils.magic: Internal.eventBlock => {"id": string, "time": int})
|
|
57
60
|
eventItem->RawEvent.make(
|
|
58
61
|
~block=payload.block,
|
|
59
62
|
~transaction=payload.transaction,
|
|
60
63
|
~params=payload.params,
|
|
61
64
|
~srcAddress=payload.srcAddress,
|
|
65
|
+
~blockHash=header["id"],
|
|
66
|
+
~blockTimestamp=header["time"],
|
|
62
67
|
~cleanUpRawEventFieldsInPlace,
|
|
63
68
|
)
|
|
64
69
|
},
|
package/src/sources/Fuel.res.mjs
CHANGED
|
@@ -19,12 +19,12 @@ function make(logger) {
|
|
|
19
19
|
cleanUpRawEventFieldsInPlace: cleanUpRawEventFieldsInPlace,
|
|
20
20
|
onBlockMethodName: "onBlock",
|
|
21
21
|
onBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
|
|
22
|
-
onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
|
|
22
|
+
onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.strict(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown)))))),
|
|
23
23
|
logger: logger,
|
|
24
24
|
toEvent: eventItem => eventItem.payload,
|
|
25
25
|
toEventLogger: eventItem => Logging.createChildFrom(logger, {
|
|
26
|
-
contract: eventItem.eventConfig.contractName,
|
|
27
|
-
event: eventItem.eventConfig.name,
|
|
26
|
+
contract: eventItem.onEventRegistration.eventConfig.contractName,
|
|
27
|
+
event: eventItem.onEventRegistration.eventConfig.name,
|
|
28
28
|
chainId: eventItem.chain,
|
|
29
29
|
block: eventItem.blockNumber,
|
|
30
30
|
logIndex: eventItem.logIndex,
|
|
@@ -32,7 +32,8 @@ function make(logger) {
|
|
|
32
32
|
}),
|
|
33
33
|
toRawEvent: eventItem => {
|
|
34
34
|
let payload = eventItem.payload;
|
|
35
|
-
|
|
35
|
+
let header = payload.block;
|
|
36
|
+
return RawEvent.make(eventItem, payload.block, payload.transaction, payload.params, payload.srcAddress, header.id, header.time, cleanUpRawEventFieldsInPlace);
|
|
36
37
|
}
|
|
37
38
|
};
|
|
38
39
|
}
|