envio 3.3.0-alpha.1 → 3.3.0-alpha.11
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/evm.schema.json +10 -0
- package/index.d.ts +45 -25
- package/licenses/CLA.md +35 -0
- package/licenses/EULA.md +67 -0
- package/licenses/LICENSE.md +45 -0
- package/licenses/README.md +35 -0
- package/package.json +10 -9
- package/src/Address.res +5 -2
- package/src/Address.res.mjs +3 -1
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/Batch.res +0 -6
- package/src/Batch.res.mjs +1 -12
- package/src/BatchProcessing.res +7 -12
- package/src/BatchProcessing.res.mjs +8 -7
- package/src/Bin.res +3 -0
- package/src/Bin.res.mjs +4 -0
- package/src/ChainFetching.res +53 -16
- package/src/ChainFetching.res.mjs +37 -19
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +630 -161
- package/src/ChainState.res.mjs +438 -101
- package/src/ChainState.resi +77 -4
- package/src/Config.res +70 -38
- package/src/Config.res.mjs +52 -12
- package/src/ContractRegisterContext.res +2 -12
- package/src/ContractRegisterContext.res.mjs +3 -5
- package/src/Core.res +34 -3
- package/src/Core.res.mjs +12 -0
- package/src/CrossChainState.res +130 -89
- package/src/CrossChainState.res.mjs +66 -61
- package/src/CrossChainState.resi +1 -1
- package/src/Ecosystem.res +5 -6
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Envio.res +17 -11
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +191 -127
- package/src/EventConfigBuilder.res.mjs +116 -66
- package/src/EventProcessing.res +77 -28
- package/src/EventProcessing.res.mjs +56 -29
- package/src/ExitOnCaughtUp.res +10 -2
- package/src/ExitOnCaughtUp.res.mjs +10 -1
- package/src/FetchState.res +684 -415
- package/src/FetchState.res.mjs +505 -486
- package/src/HandlerLoader.res +8 -104
- package/src/HandlerLoader.res.mjs +2 -81
- package/src/HandlerRegister.res +520 -144
- package/src/HandlerRegister.res.mjs +286 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerState.res +10 -3
- package/src/IndexerState.res.mjs +11 -4
- package/src/IndexerState.resi +2 -1
- package/src/IndexingAddresses.res +108 -0
- package/src/IndexingAddresses.res.mjs +101 -0
- package/src/IndexingAddresses.resi +34 -0
- package/src/Internal.res +166 -48
- package/src/Internal.res.mjs +30 -2
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/LogSelection.res +92 -217
- package/src/LogSelection.res.mjs +95 -184
- package/src/Main.res +71 -236
- package/src/Main.res.mjs +60 -145
- package/src/Metrics.res +74 -0
- package/src/Metrics.res.mjs +75 -0
- package/src/PgStorage.res +4 -4
- package/src/PgStorage.res.mjs +5 -5
- package/src/Prometheus.res +10 -63
- package/src/Prometheus.res.mjs +124 -171
- package/src/PruneStaleHistory.res +2 -2
- package/src/PruneStaleHistory.res.mjs +3 -3
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/Rollback.res +3 -3
- package/src/Rollback.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateDeadInputTracker.res +85 -0
- package/src/SimulateDeadInputTracker.res.mjs +73 -0
- package/src/SimulateDeadInputTracker.resi +12 -0
- package/src/SimulateItems.res +128 -28
- package/src/SimulateItems.res.mjs +82 -40
- package/src/TestIndexer.res +55 -41
- package/src/TestIndexer.res.mjs +39 -32
- package/src/TopicFilter.res +1 -25
- package/src/TopicFilter.res.mjs +0 -74
- package/src/bindings/Performance.res +7 -0
- package/src/bindings/Performance.res.mjs +21 -0
- package/src/bindings/Performance.resi +7 -0
- package/src/bindings/Viem.res +0 -46
- package/src/bindings/Viem.res.mjs +1 -43
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +31 -49
- package/src/sources/EventRouter.res.mjs +12 -25
- package/src/sources/Evm.res +83 -72
- package/src/sources/Evm.res.mjs +53 -69
- package/src/sources/EvmChain.res +7 -34
- package/src/sources/EvmChain.res.mjs +6 -27
- package/src/sources/EvmRpcClient.res +71 -5
- package/src/sources/EvmRpcClient.res.mjs +13 -4
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +9 -6
- package/src/sources/Fuel.res.mjs +5 -10
- package/src/sources/HyperFuelSource.res +46 -50
- package/src/sources/HyperFuelSource.res.mjs +64 -54
- package/src/sources/HyperSync.res +45 -42
- package/src/sources/HyperSync.res.mjs +68 -60
- package/src/sources/HyperSync.resi +14 -4
- package/src/sources/HyperSyncClient.res +107 -119
- package/src/sources/HyperSyncClient.res.mjs +36 -31
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +60 -254
- package/src/sources/HyperSyncSource.res.mjs +57 -180
- package/src/sources/Rpc.res +15 -79
- package/src/sources/Rpc.res.mjs +25 -101
- package/src/sources/RpcSource.res +221 -514
- package/src/sources/RpcSource.res.mjs +216 -411
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +44 -20
- package/src/sources/SimulateSource.res.mjs +41 -14
- package/src/sources/Source.res +34 -6
- package/src/sources/SourceManager.res +77 -19
- package/src/sources/SourceManager.res.mjs +63 -21
- package/src/sources/SourceManager.resi +10 -0
- package/src/sources/Svm.res +31 -16
- package/src/sources/Svm.res.mjs +36 -13
- package/src/sources/SvmHyperSyncClient.res +5 -32
- package/src/sources/SvmHyperSyncSource.res +159 -134
- package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
- package/src/sources/TransactionStore.res +49 -0
- package/src/sources/TransactionStore.res.mjs +30 -0
- package/src/tui/Tui.res +13 -16
- package/src/tui/Tui.res.mjs +12 -14
- package/svm.schema.json +49 -37
- package/src/bindings/Hrtime.res +0 -58
- package/src/bindings/Hrtime.res.mjs +0 -90
- package/src/bindings/Hrtime.resi +0 -30
package/src/IndexerState.resi
CHANGED
|
@@ -44,7 +44,7 @@ let makeFromDbState: (
|
|
|
44
44
|
~config: Config.t,
|
|
45
45
|
~persistence: Persistence.t,
|
|
46
46
|
~initialState: Persistence.initialState,
|
|
47
|
-
~
|
|
47
|
+
~registrationsByChainId: HandlerRegister.registrationsByChainId,
|
|
48
48
|
~isDevelopmentMode: bool=?,
|
|
49
49
|
~shouldUseTui: bool=?,
|
|
50
50
|
~exitAfterFirstEventBlock: bool=?,
|
|
@@ -107,6 +107,7 @@ let exitAfterFirstEventBlock: t => bool
|
|
|
107
107
|
let isStopped: t => bool
|
|
108
108
|
let epoch: t => int
|
|
109
109
|
let pruneStaleEntityHistoryThrottler: t => Throttler.t
|
|
110
|
+
let simulateDeadInputTracker: t => option<SimulateDeadInputTracker.t>
|
|
110
111
|
|
|
111
112
|
// Store domain operations.
|
|
112
113
|
let queueProcessedBatch: (t, ~batch: Batch.t) => unit
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
type indexingAddress = Internal.indexingContract
|
|
2
|
+
|
|
3
|
+
type contractConfig = {startBlock: option<int>}
|
|
4
|
+
|
|
5
|
+
type t = dict<indexingAddress>
|
|
6
|
+
|
|
7
|
+
let deriveEffectiveStartBlock = (~registrationBlock: int, ~contractStartBlock: option<int>) => {
|
|
8
|
+
Pervasives.max(Pervasives.max(registrationBlock, 0), contractStartBlock->Option.getOr(0))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let makeContractConfigs = (~onEventRegistrations: array<Internal.onEventRegistration>): dict<
|
|
12
|
+
contractConfig,
|
|
13
|
+
> => {
|
|
14
|
+
let contractConfigs: dict<contractConfig> = Dict.make()
|
|
15
|
+
onEventRegistrations->Array.forEach(reg => {
|
|
16
|
+
let contractName = reg.eventConfig.contractName
|
|
17
|
+
switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
18
|
+
| Some({startBlock}) =>
|
|
19
|
+
contractConfigs->Dict.set(
|
|
20
|
+
contractName,
|
|
21
|
+
{
|
|
22
|
+
startBlock: switch (startBlock, reg.startBlock) {
|
|
23
|
+
| (Some(a), Some(b)) => Some(Pervasives.min(a, b))
|
|
24
|
+
| (Some(_) as s, None) | (None, Some(_) as s) => s
|
|
25
|
+
| (None, None) => None
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
)
|
|
29
|
+
| None =>
|
|
30
|
+
contractConfigs->Dict.set(
|
|
31
|
+
contractName,
|
|
32
|
+
{
|
|
33
|
+
startBlock: reg.startBlock,
|
|
34
|
+
},
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
contractConfigs
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let makeIndexingAddress = (
|
|
42
|
+
~contract: Internal.indexingAddress,
|
|
43
|
+
~contractConfigs: dict<contractConfig>,
|
|
44
|
+
): indexingAddress => {
|
|
45
|
+
let contractStartBlock = switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(
|
|
46
|
+
contract.contractName,
|
|
47
|
+
) {
|
|
48
|
+
| Some({startBlock}) => startBlock
|
|
49
|
+
| None => None
|
|
50
|
+
}
|
|
51
|
+
{
|
|
52
|
+
address: contract.address,
|
|
53
|
+
contractName: contract.contractName,
|
|
54
|
+
registrationBlock: contract.registrationBlock,
|
|
55
|
+
effectiveStartBlock: deriveEffectiveStartBlock(
|
|
56
|
+
~registrationBlock=contract.registrationBlock,
|
|
57
|
+
~contractStartBlock,
|
|
58
|
+
),
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let make = (
|
|
63
|
+
~contractConfigs: dict<contractConfig>,
|
|
64
|
+
~addresses: array<Internal.indexingAddress>,
|
|
65
|
+
): t => {
|
|
66
|
+
let indexingAddresses = Dict.make()
|
|
67
|
+
addresses->Array.forEach(contract => {
|
|
68
|
+
indexingAddresses->Dict.set(
|
|
69
|
+
contract.address->Address.toString,
|
|
70
|
+
makeIndexingAddress(~contract, ~contractConfigs),
|
|
71
|
+
)
|
|
72
|
+
})
|
|
73
|
+
indexingAddresses
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let get = (indexingAddresses: t, address) =>
|
|
77
|
+
indexingAddresses->Utils.Dict.dangerouslyGetNonOption(address)
|
|
78
|
+
|
|
79
|
+
let size = (indexingAddresses: t) => indexingAddresses->Utils.Dict.size
|
|
80
|
+
|
|
81
|
+
let getContractAddresses = (indexingAddresses: t, ~contractName): array<Address.t> => {
|
|
82
|
+
let addresses = []
|
|
83
|
+
indexingAddresses->Utils.Dict.forEach(ia => {
|
|
84
|
+
if ia.contractName === contractName {
|
|
85
|
+
addresses->Array.push(ia.address)
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
addresses
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Underlying dict for the precompiled `clientAddressFilter` only — it does raw
|
|
92
|
+
// `indexingAddresses[srcAddress]` access in generated JS and can't take the opaque
|
|
93
|
+
// type. Don't reach for this elsewhere; use the domain accessors above.
|
|
94
|
+
let rawForFilter = (indexingAddresses: t): dict<indexingAddress> => indexingAddresses
|
|
95
|
+
|
|
96
|
+
let register = (indexingAddresses: t, additions: dict<indexingAddress>) => {
|
|
97
|
+
let _ = Utils.Dict.mergeInPlace(indexingAddresses, additions)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let rollbackInPlace = (indexingAddresses: t, ~targetBlockNumber: int): unit => {
|
|
101
|
+
// forEachWithKey is a `for..in`, so deleting the key currently being visited is
|
|
102
|
+
// safe — it doesn't affect enumeration of the remaining keys.
|
|
103
|
+
indexingAddresses->Utils.Dict.forEachWithKey((indexingContract, address) => {
|
|
104
|
+
if indexingContract.registrationBlock > targetBlockNumber {
|
|
105
|
+
indexingAddresses->Utils.Dict.deleteInPlace(address)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Utils from "./Utils.res.mjs";
|
|
4
|
+
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
|
|
7
|
+
function deriveEffectiveStartBlock(registrationBlock, contractStartBlock) {
|
|
8
|
+
return Primitive_int.max(Primitive_int.max(registrationBlock, 0), Stdlib_Option.getOr(contractStartBlock, 0));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function makeContractConfigs(onEventRegistrations) {
|
|
12
|
+
let contractConfigs = {};
|
|
13
|
+
onEventRegistrations.forEach(reg => {
|
|
14
|
+
let contractName = reg.eventConfig.contractName;
|
|
15
|
+
let match = contractConfigs[contractName];
|
|
16
|
+
if (match !== undefined) {
|
|
17
|
+
let startBlock = match.startBlock;
|
|
18
|
+
let match$1 = reg.startBlock;
|
|
19
|
+
contractConfigs[contractName] = {
|
|
20
|
+
startBlock: startBlock !== undefined ? (
|
|
21
|
+
match$1 !== undefined ? Primitive_int.min(startBlock, match$1) : startBlock
|
|
22
|
+
) : (
|
|
23
|
+
match$1 !== undefined ? match$1 : undefined
|
|
24
|
+
)
|
|
25
|
+
};
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
contractConfigs[contractName] = {
|
|
29
|
+
startBlock: reg.startBlock
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
return contractConfigs;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function makeIndexingAddress(contract, contractConfigs) {
|
|
36
|
+
let match = contractConfigs[contract.contractName];
|
|
37
|
+
let contractStartBlock = match !== undefined ? match.startBlock : undefined;
|
|
38
|
+
return {
|
|
39
|
+
address: contract.address,
|
|
40
|
+
contractName: contract.contractName,
|
|
41
|
+
registrationBlock: contract.registrationBlock,
|
|
42
|
+
effectiveStartBlock: deriveEffectiveStartBlock(contract.registrationBlock, contractStartBlock)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function make(contractConfigs, addresses) {
|
|
47
|
+
let indexingAddresses = {};
|
|
48
|
+
addresses.forEach(contract => {
|
|
49
|
+
indexingAddresses[contract.address] = makeIndexingAddress(contract, contractConfigs);
|
|
50
|
+
});
|
|
51
|
+
return indexingAddresses;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function get(indexingAddresses, address) {
|
|
55
|
+
return indexingAddresses[address];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function size(indexingAddresses) {
|
|
59
|
+
return Utils.Dict.size(indexingAddresses);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getContractAddresses(indexingAddresses, contractName) {
|
|
63
|
+
let addresses = [];
|
|
64
|
+
Utils.Dict.forEach(indexingAddresses, ia => {
|
|
65
|
+
if (ia.contractName === contractName) {
|
|
66
|
+
addresses.push(ia.address);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return addresses;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function rawForFilter(indexingAddresses) {
|
|
74
|
+
return indexingAddresses;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function register(indexingAddresses, additions) {
|
|
78
|
+
Object.assign(indexingAddresses, additions);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function rollbackInPlace(indexingAddresses, targetBlockNumber) {
|
|
82
|
+
Utils.Dict.forEachWithKey(indexingAddresses, (indexingContract, address) => {
|
|
83
|
+
if (indexingContract.registrationBlock > targetBlockNumber) {
|
|
84
|
+
return Utils.Dict.deleteInPlace(indexingAddresses, address);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
deriveEffectiveStartBlock,
|
|
91
|
+
makeContractConfigs,
|
|
92
|
+
makeIndexingAddress,
|
|
93
|
+
make,
|
|
94
|
+
get,
|
|
95
|
+
size,
|
|
96
|
+
getContractAddresses,
|
|
97
|
+
rawForFilter,
|
|
98
|
+
register,
|
|
99
|
+
rollbackInPlace,
|
|
100
|
+
}
|
|
101
|
+
/* Utils Not a pure module */
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type indexingAddress = Internal.indexingContract
|
|
2
|
+
|
|
3
|
+
type contractConfig = {startBlock: option<int>}
|
|
4
|
+
|
|
5
|
+
type t
|
|
6
|
+
|
|
7
|
+
let deriveEffectiveStartBlock: (~registrationBlock: int, ~contractStartBlock: option<int>) => int
|
|
8
|
+
|
|
9
|
+
let makeContractConfigs: (
|
|
10
|
+
~onEventRegistrations: array<Internal.onEventRegistration>,
|
|
11
|
+
) => dict<contractConfig>
|
|
12
|
+
|
|
13
|
+
let makeIndexingAddress: (
|
|
14
|
+
~contract: Internal.indexingAddress,
|
|
15
|
+
~contractConfigs: dict<contractConfig>,
|
|
16
|
+
) => indexingAddress
|
|
17
|
+
|
|
18
|
+
let make: (~contractConfigs: dict<contractConfig>, ~addresses: array<Internal.indexingAddress>) => t
|
|
19
|
+
|
|
20
|
+
let get: (t, string) => option<indexingAddress>
|
|
21
|
+
|
|
22
|
+
let size: t => int
|
|
23
|
+
|
|
24
|
+
let getContractAddresses: (t, ~contractName: string) => array<Address.t>
|
|
25
|
+
|
|
26
|
+
// Underlying dict for the precompiled `clientAddressFilter` only, which does raw
|
|
27
|
+
// `indexingAddresses[srcAddress]` access in generated JS. Don't use elsewhere —
|
|
28
|
+
// prefer the domain accessors so the opaque type stays enforced.
|
|
29
|
+
let rawForFilter: t => dict<indexingAddress>
|
|
30
|
+
|
|
31
|
+
let register: (t, dict<indexingAddress>) => unit
|
|
32
|
+
|
|
33
|
+
// Deletes addresses registered after `targetBlockNumber` from the index in place.
|
|
34
|
+
let rollbackInPlace: (t, ~targetBlockNumber: int) => unit
|
package/src/Internal.res
CHANGED
|
@@ -58,7 +58,6 @@ type evmTransactionField =
|
|
|
58
58
|
| @as("root") Root
|
|
59
59
|
| @as("status") Status
|
|
60
60
|
| @as("yParity") YParity
|
|
61
|
-
| @as("accessList") AccessList
|
|
62
61
|
| @as("maxFeePerBlobGas") MaxFeePerBlobGas
|
|
63
62
|
| @as("blobVersionedHashes") BlobVersionedHashes
|
|
64
63
|
| @as("type") Type
|
|
@@ -67,6 +66,7 @@ type evmTransactionField =
|
|
|
67
66
|
| @as("l1GasUsed") L1GasUsed
|
|
68
67
|
| @as("l1FeeScalar") L1FeeScalar
|
|
69
68
|
| @as("gasUsedForL1") GasUsedForL1
|
|
69
|
+
| @as("accessList") AccessList
|
|
70
70
|
| @as("authorizationList") AuthorizationList
|
|
71
71
|
|
|
72
72
|
let allEvmBlockFields: array<evmBlockField> = [
|
|
@@ -123,7 +123,6 @@ let allEvmTransactionFields: array<evmTransactionField> = [
|
|
|
123
123
|
Root,
|
|
124
124
|
Status,
|
|
125
125
|
YParity,
|
|
126
|
-
AccessList,
|
|
127
126
|
MaxFeePerBlobGas,
|
|
128
127
|
BlobVersionedHashes,
|
|
129
128
|
Type,
|
|
@@ -132,10 +131,54 @@ let allEvmTransactionFields: array<evmTransactionField> = [
|
|
|
132
131
|
L1GasUsed,
|
|
133
132
|
L1FeeScalar,
|
|
134
133
|
GasUsedForL1,
|
|
134
|
+
AccessList,
|
|
135
135
|
AuthorizationList,
|
|
136
136
|
]
|
|
137
137
|
let evmTransactionFieldSchema = S.enum(allEvmTransactionFields)
|
|
138
138
|
|
|
139
|
+
// SVM transaction fields. Order mirrors the Rust `SvmTxField` ordinals (the bit
|
|
140
|
+
// position in the selection mask) and `Svm.res` `transactionFields`.
|
|
141
|
+
type svmTransactionField =
|
|
142
|
+
| @as("transactionIndex") TransactionIndex
|
|
143
|
+
| @as("signatures") Signatures
|
|
144
|
+
| @as("feePayer") FeePayer
|
|
145
|
+
| @as("success") Success
|
|
146
|
+
| @as("err") Err
|
|
147
|
+
| @as("fee") Fee
|
|
148
|
+
| @as("computeUnitsConsumed") ComputeUnitsConsumed
|
|
149
|
+
| @as("accountKeys") AccountKeys
|
|
150
|
+
| @as("recentBlockhash") RecentBlockhash
|
|
151
|
+
| @as("version") Version
|
|
152
|
+
| @as("tokenBalances") TokenBalances
|
|
153
|
+
|
|
154
|
+
let allSvmTransactionFields: array<svmTransactionField> = [
|
|
155
|
+
TransactionIndex,
|
|
156
|
+
Signatures,
|
|
157
|
+
FeePayer,
|
|
158
|
+
Success,
|
|
159
|
+
Err,
|
|
160
|
+
Fee,
|
|
161
|
+
ComputeUnitsConsumed,
|
|
162
|
+
AccountKeys,
|
|
163
|
+
RecentBlockhash,
|
|
164
|
+
Version,
|
|
165
|
+
TokenBalances,
|
|
166
|
+
]
|
|
167
|
+
let svmTransactionFieldSchema = S.enum(allSvmTransactionFields)
|
|
168
|
+
|
|
169
|
+
// All SVM block fields. `slot`/`time`/`hash` are always included; the rest are
|
|
170
|
+
// selectable via `field_selection.block_fields` (see `allSvmBlockFields`).
|
|
171
|
+
type svmBlockField =
|
|
172
|
+
| @as("slot") Slot
|
|
173
|
+
| @as("time") Time
|
|
174
|
+
| @as("hash") Hash
|
|
175
|
+
| @as("height") Height
|
|
176
|
+
| @as("parentSlot") ParentSlot
|
|
177
|
+
| @as("parentHash") ParentHash
|
|
178
|
+
|
|
179
|
+
let allSvmBlockFields: array<svmBlockField> = [Height, ParentSlot, ParentHash]
|
|
180
|
+
let svmBlockFieldSchema = S.enum(allSvmBlockFields)
|
|
181
|
+
|
|
139
182
|
// Static sets of nullable field names — used by RpcSource and HyperSyncSource to wrap schemas with S.nullable
|
|
140
183
|
let evmNullableBlockFields = Utils.Set.fromArray(
|
|
141
184
|
(
|
|
@@ -265,8 +308,8 @@ type genericEvent<'params, 'block, 'transaction> = {
|
|
|
265
308
|
block: 'block,
|
|
266
309
|
}
|
|
267
310
|
|
|
268
|
-
// Opaque internally — block
|
|
269
|
-
//
|
|
311
|
+
// Opaque internally — the block number needed by the runtime lives on the
|
|
312
|
+
// item instead.
|
|
270
313
|
type event
|
|
271
314
|
|
|
272
315
|
// Opaque payload an item carries. A source builds an ecosystem-specific
|
|
@@ -277,7 +320,18 @@ type event
|
|
|
277
320
|
// modules, not here, and are distinct per ecosystem.
|
|
278
321
|
type eventPayload
|
|
279
322
|
|
|
280
|
-
|
|
323
|
+
// Generic access to the payload's `transaction`, written at batch prep for
|
|
324
|
+
// store-backed ecosystems (HyperSync) and present inline otherwise.
|
|
325
|
+
@get external getPayloadTransaction: eventPayload => Nullable.t<eventTransaction> = "transaction"
|
|
326
|
+
@set external setPayloadTransaction: (eventPayload, eventTransaction) => unit = "transaction"
|
|
327
|
+
|
|
328
|
+
// Generic access to the payload's `block`: written/enriched at batch prep for
|
|
329
|
+
// store-backed ecosystems (EVM/SVM HyperSync) and present inline otherwise.
|
|
330
|
+
@get external getPayloadBlock: eventPayload => Nullable.t<eventBlock> = "block"
|
|
331
|
+
@set external setPayloadBlock: (eventPayload, eventBlock) => unit = "block"
|
|
332
|
+
|
|
333
|
+
// The log's emitting address (EVM/Fuel; the program id carries it for SVM).
|
|
334
|
+
@get external getPayloadSrcAddress: eventPayload => Address.t = "srcAddress"
|
|
281
335
|
|
|
282
336
|
type genericLoaderArgs<'event, 'context> = {
|
|
283
337
|
event: 'event,
|
|
@@ -357,31 +411,33 @@ type indexingContract = {
|
|
|
357
411
|
effectiveStartBlock: int,
|
|
358
412
|
}
|
|
359
413
|
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
414
|
+
// Definition of an event/instruction we know how to decode: identity + decode
|
|
415
|
+
// schemas + chain-independent field selection. A pure function of the ABI +
|
|
416
|
+
// config, shared across chains. `private` so it can only be coerced from an
|
|
417
|
+
// ecosystem variant (fields never overwritten), which lets sources cast the
|
|
418
|
+
// base back down to evm/fuel/svm safely.
|
|
364
419
|
type eventConfig = private {
|
|
365
420
|
id: string,
|
|
366
421
|
name: string,
|
|
367
422
|
contractName: string,
|
|
368
|
-
isWildcard: bool,
|
|
369
|
-
// Whether the event has an event filter which uses addresses
|
|
370
|
-
filterByAddresses: bool,
|
|
371
|
-
// Usually always false for wildcard events
|
|
372
|
-
// But might be true for wildcard event with dynamic event filter by addresses
|
|
373
|
-
dependsOnAddresses: bool,
|
|
374
|
-
// Precompiled predicate (EVM only) for events that filter an indexed address
|
|
375
|
-
// param by registered addresses. Given the decoded event and the log's block
|
|
376
|
-
// number, drops an event whose param-address isn't registered at/before that
|
|
377
|
-
// block — the param-level analogue of EventRouter's srcAddress
|
|
378
|
-
// `effectiveStartBlock` check. Absent otherwise.
|
|
379
|
-
clientAddressFilter?: (eventPayload, int, dict<indexingContract>) => bool,
|
|
380
|
-
handler: option<handler>,
|
|
381
|
-
contractRegister: option<contractRegister>,
|
|
382
423
|
paramsRawEventSchema: S.schema<eventParams>,
|
|
383
424
|
simulateParamsSchema: S.schema<eventParams>,
|
|
384
|
-
|
|
425
|
+
// Field names selected for the chain's transaction-store materialisation
|
|
426
|
+
// (camelCase, matching the ecosystem's `transactionFields`). Stored as a
|
|
427
|
+
// string set so the shared mask logic is ecosystem-agnostic; sources recover
|
|
428
|
+
// the typed view where they need it.
|
|
429
|
+
selectedTransactionFields: Utils.Set.t<string>,
|
|
430
|
+
// `selectedTransactionFields` precompiled to the transaction-store selection
|
|
431
|
+
// bitmask (bit per ecosystem field code). Materialisation reads this per item
|
|
432
|
+
// so each transaction decodes only the fields its event selected. `0.` when
|
|
433
|
+
// nothing is selected or the ecosystem carries the transaction inline (Fuel).
|
|
434
|
+
transactionFieldMask: float,
|
|
435
|
+
// Selected block fields precompiled to the block-store selection bitmask (bit
|
|
436
|
+
// per ecosystem field code). `0.` for ecosystems that carry the block fully
|
|
437
|
+
// inline (RPC/Fuel). The EVM selection always includes number/timestamp/hash,
|
|
438
|
+
// so an EVM mask always has their bits set; SVM stamps slot/time/hash inline
|
|
439
|
+
// from the response and its mask is the user's selection alone.
|
|
440
|
+
blockFieldMask: float,
|
|
385
441
|
}
|
|
386
442
|
|
|
387
443
|
type fuelEventKind =
|
|
@@ -406,30 +462,46 @@ type topicSelection = {
|
|
|
406
462
|
topic3: array<EvmTypes.Hex.t>,
|
|
407
463
|
}
|
|
408
464
|
|
|
465
|
+
// A single topic position of a resolved `where`: either static pre-encoded
|
|
466
|
+
// values, or a marker for "the currently registered addresses of this
|
|
467
|
+
// contract", expanded to topic values when a source query is built.
|
|
468
|
+
type topicFilter =
|
|
469
|
+
| Values(array<EvmTypes.Hex.t>)
|
|
470
|
+
| ContractAddresses({contractName: string})
|
|
471
|
+
|
|
472
|
+
type resolvedTopicSelection = {
|
|
473
|
+
topic0: array<EvmTypes.Hex.t>,
|
|
474
|
+
topic1: topicFilter,
|
|
475
|
+
topic2: topicFilter,
|
|
476
|
+
topic3: topicFilter,
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// The registered `where` fully resolved at registration time for one chain.
|
|
480
|
+
// `topicSelections` is in disjunctive normal form (outer array is OR);
|
|
481
|
+
// an empty array means the `where` returned `false` for this chain.
|
|
482
|
+
type resolvedWhere = {
|
|
483
|
+
topicSelections: array<resolvedTopicSelection>,
|
|
484
|
+
startBlock: option<int>,
|
|
485
|
+
}
|
|
486
|
+
|
|
409
487
|
// Per-event, per-invocation arguments passed to a `where` callback. The
|
|
410
488
|
// concrete `chain` shape (which contract key it exposes) is generated per
|
|
411
489
|
// event in user-project codegen — here it's an open record so codegen'd
|
|
412
490
|
// types subtype-coerce into it cleanly.
|
|
413
491
|
type onEventWhereArgs<'chain> = {chain: 'chain}
|
|
414
492
|
|
|
415
|
-
type eventFilters =
|
|
416
|
-
Static(array<topicSelection>) | Dynamic(array<Address.t> => array<topicSelection>)
|
|
417
|
-
|
|
418
493
|
type evmEventConfig = {
|
|
419
494
|
...eventConfig,
|
|
420
|
-
getEventFiltersOrThrow: ChainMap.Chain.t => eventFilters,
|
|
421
495
|
selectedBlockFields: Utils.Set.t<evmBlockField>,
|
|
422
|
-
selectedTransactionFields: Utils.Set.t<evmTransactionField>,
|
|
423
496
|
sighash: string,
|
|
424
497
|
topicCount: int,
|
|
425
498
|
paramsMetadata: array<paramMeta>,
|
|
426
499
|
}
|
|
427
500
|
|
|
428
|
-
// Shared formula for `
|
|
429
|
-
// `EventConfigBuilder.build
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
// there simply pass it through as `false`.
|
|
501
|
+
// Shared formula for a registration's `dependsOnAddresses`. Kept here so the
|
|
502
|
+
// `EventConfigBuilder.build*OnEventRegistration` builders stay in sync. Fuel
|
|
503
|
+
// and SVM events always have `filterByAddresses=false`, so callers there pass
|
|
504
|
+
// it through as `false`.
|
|
433
505
|
let dependsOnAddresses = (~isWildcard, ~filterByAddresses) => !isWildcard || filterByAddresses
|
|
434
506
|
|
|
435
507
|
type evmContractConfig = {
|
|
@@ -448,6 +520,10 @@ type svmAccountFilterGroup = array<svmAccountFilter>
|
|
|
448
520
|
|
|
449
521
|
type svmInstructionEventConfig = {
|
|
450
522
|
...eventConfig,
|
|
523
|
+
/** Block fields selected via `field_selection.block_fields` (`slot` is always
|
|
524
|
+
included and excluded from this set). Drives the block query columns;
|
|
525
|
+
precompiled to `blockFieldMask` for store materialisation. */
|
|
526
|
+
selectedBlockFields: Utils.Set.t<svmBlockField>,
|
|
451
527
|
/** Base58 Solana program id this instruction belongs to. */
|
|
452
528
|
programId: SvmTypes.Pubkey.t,
|
|
453
529
|
/** Hex-encoded discriminator. `None` matches every instruction in the program. */
|
|
@@ -456,9 +532,7 @@ type svmInstructionEventConfig = {
|
|
|
456
532
|
`dN` selector at query time and the dispatch-key precomputation in the
|
|
457
533
|
router. */
|
|
458
534
|
discriminatorByteLen: int,
|
|
459
|
-
includeTransaction: bool,
|
|
460
535
|
includeLogs: bool,
|
|
461
|
-
includeTokenBalances: bool,
|
|
462
536
|
/** Disjunctive normal form: outer array is OR of AND-groups, inner array is
|
|
463
537
|
AND across positions. Empty outer array means "no account filter". */
|
|
464
538
|
accountFilters: array<svmAccountFilterGroup>,
|
|
@@ -476,6 +550,49 @@ type svmInstructionEventConfig = {
|
|
|
476
550
|
definedTypes: JSON.t,
|
|
477
551
|
}
|
|
478
552
|
|
|
553
|
+
// Per-(event, chain) registration produced when user handler code registers an
|
|
554
|
+
// event (`onEvent`) or a dynamic contract registers. References its definition
|
|
555
|
+
// by value as `.eventConfig` and adds the handler binding plus the
|
|
556
|
+
// registration/`where`-derived fetch state. Not `private`: Fuel/SVM
|
|
557
|
+
// registrations add no ecosystem-specific fields (so they're bare aliases that
|
|
558
|
+
// must stay directly constructable), and the evm→base cast in sources is sound
|
|
559
|
+
// by ecosystem homogeneity — an EVM chain only ever holds `evmOnEventRegistration`s.
|
|
560
|
+
type onEventRegistration = {
|
|
561
|
+
// Chain-scoped sequential index — the registration's position in the
|
|
562
|
+
// chain's onEventRegistrations array, assigned when registration finishes
|
|
563
|
+
// (-1 until then). Native-routed items reference their registration by this
|
|
564
|
+
// index across the napi boundary; sources resolve it before creating an item.
|
|
565
|
+
index: int,
|
|
566
|
+
eventConfig: eventConfig,
|
|
567
|
+
handler: option<handler>,
|
|
568
|
+
contractRegister: option<contractRegister>,
|
|
569
|
+
isWildcard: bool,
|
|
570
|
+
// Whether the event has an event filter which uses addresses.
|
|
571
|
+
filterByAddresses: bool,
|
|
572
|
+
// Usually always false for wildcard events, but might be true for a wildcard
|
|
573
|
+
// event with a dynamic event filter by addresses.
|
|
574
|
+
dependsOnAddresses: bool,
|
|
575
|
+
// Precompiled predicate for events that filter an indexed address param by
|
|
576
|
+
// registered addresses (see `EventConfigBuilder.buildAddressFilter`); drops a
|
|
577
|
+
// decoded event whose param-address isn't registered at/before the log's
|
|
578
|
+
// block. Absent otherwise.
|
|
579
|
+
clientAddressFilter?: (eventPayload, int, dict<indexingContract>) => bool,
|
|
580
|
+
// Final start block: the contract/chain config value, overridden by a
|
|
581
|
+
// `where.block.number._gte` when the registered `where` supplies one.
|
|
582
|
+
startBlock: option<int>,
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
type evmOnEventRegistration = {
|
|
586
|
+
...onEventRegistration,
|
|
587
|
+
resolvedWhere: resolvedWhere,
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Fuel and SVM registrations add no ecosystem-specific fetch state (their
|
|
591
|
+
// filters are config-derived and live on the definition), so they're bare
|
|
592
|
+
// aliases of the base registration.
|
|
593
|
+
type fuelOnEventRegistration = onEventRegistration
|
|
594
|
+
type svmOnEventRegistration = onEventRegistration
|
|
595
|
+
|
|
479
596
|
type svmProgramConfig = {
|
|
480
597
|
name: string,
|
|
481
598
|
programId: SvmTypes.Pubkey.t,
|
|
@@ -492,16 +609,18 @@ type indexingAddress = {
|
|
|
492
609
|
|
|
493
610
|
type dcs = array<indexingAddress>
|
|
494
611
|
|
|
495
|
-
// Duplicate the type from item
|
|
496
|
-
//
|
|
612
|
+
// Duplicate the type from item to keep item properly unboxed. Runtime event
|
|
613
|
+
// items carry the registration their source already resolved from the
|
|
614
|
+
// ChainState-owned registration array.
|
|
497
615
|
type eventItem = private {
|
|
498
616
|
kind: [#0],
|
|
499
|
-
|
|
500
|
-
timestamp: int,
|
|
617
|
+
onEventRegistration: onEventRegistration,
|
|
501
618
|
chain: ChainMap.Chain.t,
|
|
502
619
|
blockNumber: int,
|
|
503
|
-
blockHash: string,
|
|
504
620
|
logIndex: int,
|
|
621
|
+
// Within-block transaction index — the key into the per-chain transaction
|
|
622
|
+
// store. Unused (0) for ecosystems that carry the transaction inline (Fuel).
|
|
623
|
+
transactionIndex: int,
|
|
505
624
|
payload: eventPayload,
|
|
506
625
|
}
|
|
507
626
|
|
|
@@ -532,7 +651,7 @@ type onBlockArgs = {
|
|
|
532
651
|
context: handlerContext,
|
|
533
652
|
}
|
|
534
653
|
|
|
535
|
-
type
|
|
654
|
+
type onBlockRegistration = {
|
|
536
655
|
// When there are multiple onBlock handlers per chain,
|
|
537
656
|
// we want to use the order they are defined for sorting
|
|
538
657
|
index: int,
|
|
@@ -548,15 +667,14 @@ type onBlockConfig = {
|
|
|
548
667
|
type item =
|
|
549
668
|
| @as(0)
|
|
550
669
|
Event({
|
|
551
|
-
|
|
552
|
-
timestamp: int,
|
|
670
|
+
onEventRegistration: onEventRegistration,
|
|
553
671
|
chain: ChainMap.Chain.t,
|
|
554
672
|
blockNumber: int,
|
|
555
|
-
blockHash: string,
|
|
556
673
|
logIndex: int,
|
|
674
|
+
transactionIndex: int,
|
|
557
675
|
payload: eventPayload,
|
|
558
676
|
})
|
|
559
|
-
| @as(1) Block({
|
|
677
|
+
| @as(1) Block({onBlockRegistration: onBlockRegistration, blockNumber: int, logIndex: int})
|
|
560
678
|
|
|
561
679
|
external castUnsafeEventItem: item => eventItem = "%identity"
|
|
562
680
|
|
|
@@ -568,7 +686,7 @@ external getItemLogIndex: item => int = "logIndex"
|
|
|
568
686
|
let getItemChainId = item =>
|
|
569
687
|
switch item {
|
|
570
688
|
| Event({chain}) => chain->ChainMap.Chain.toChainId
|
|
571
|
-
| Block({
|
|
689
|
+
| Block({onBlockRegistration: {chainId}}) => chainId
|
|
572
690
|
}
|
|
573
691
|
|
|
574
692
|
@get
|
|
@@ -653,7 +771,7 @@ type effect = {
|
|
|
653
771
|
input: S.t<effectInput>,
|
|
654
772
|
// The number of functions that are currently running.
|
|
655
773
|
mutable activeCallsCount: int,
|
|
656
|
-
mutable prevCallStartTimerRef:
|
|
774
|
+
mutable prevCallStartTimerRef: Performance.timeRef,
|
|
657
775
|
rateLimit: option<rateLimitState>,
|
|
658
776
|
}
|
|
659
777
|
let cacheTablePrefix = "envio_effect_"
|
package/src/Internal.res.mjs
CHANGED
|
@@ -60,7 +60,6 @@ let allEvmTransactionFields = [
|
|
|
60
60
|
"root",
|
|
61
61
|
"status",
|
|
62
62
|
"yParity",
|
|
63
|
-
"accessList",
|
|
64
63
|
"maxFeePerBlobGas",
|
|
65
64
|
"blobVersionedHashes",
|
|
66
65
|
"type",
|
|
@@ -69,11 +68,36 @@ let allEvmTransactionFields = [
|
|
|
69
68
|
"l1GasUsed",
|
|
70
69
|
"l1FeeScalar",
|
|
71
70
|
"gasUsedForL1",
|
|
71
|
+
"accessList",
|
|
72
72
|
"authorizationList"
|
|
73
73
|
];
|
|
74
74
|
|
|
75
75
|
let evmTransactionFieldSchema = S$RescriptSchema.$$enum(allEvmTransactionFields);
|
|
76
76
|
|
|
77
|
+
let allSvmTransactionFields = [
|
|
78
|
+
"transactionIndex",
|
|
79
|
+
"signatures",
|
|
80
|
+
"feePayer",
|
|
81
|
+
"success",
|
|
82
|
+
"err",
|
|
83
|
+
"fee",
|
|
84
|
+
"computeUnitsConsumed",
|
|
85
|
+
"accountKeys",
|
|
86
|
+
"recentBlockhash",
|
|
87
|
+
"version",
|
|
88
|
+
"tokenBalances"
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
let svmTransactionFieldSchema = S$RescriptSchema.$$enum(allSvmTransactionFields);
|
|
92
|
+
|
|
93
|
+
let allSvmBlockFields = [
|
|
94
|
+
"height",
|
|
95
|
+
"parentSlot",
|
|
96
|
+
"parentHash"
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
let svmBlockFieldSchema = S$RescriptSchema.$$enum(allSvmBlockFields);
|
|
100
|
+
|
|
77
101
|
let evmNullableBlockFields = new Set([
|
|
78
102
|
"nonce",
|
|
79
103
|
"difficulty",
|
|
@@ -125,7 +149,7 @@ function getItemChainId(item) {
|
|
|
125
149
|
if (item.kind === 0) {
|
|
126
150
|
return item.chain;
|
|
127
151
|
} else {
|
|
128
|
-
return item.
|
|
152
|
+
return item.onBlockRegistration.chainId;
|
|
129
153
|
}
|
|
130
154
|
}
|
|
131
155
|
|
|
@@ -160,6 +184,10 @@ export {
|
|
|
160
184
|
evmBlockFieldSchema,
|
|
161
185
|
allEvmTransactionFields,
|
|
162
186
|
evmTransactionFieldSchema,
|
|
187
|
+
allSvmTransactionFields,
|
|
188
|
+
svmTransactionFieldSchema,
|
|
189
|
+
allSvmBlockFields,
|
|
190
|
+
svmBlockFieldSchema,
|
|
163
191
|
evmNullableBlockFields,
|
|
164
192
|
evmNullableTransactionFields,
|
|
165
193
|
dependsOnAddresses,
|