envio 3.9.0 → 3.10.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/evm.schema.json +26 -0
- package/fuel.schema.json +26 -0
- package/index.d.ts +41 -8
- package/package.json +6 -7
- package/src/Batch.res +9 -0
- package/src/ChainState.res +35 -39
- package/src/ChainState.res.mjs +14 -11
- package/src/ChainState.resi +15 -7
- package/src/Config.res +61 -44
- package/src/Config.res.mjs +56 -19
- package/src/Core.res +19 -0
- package/src/Core.res.mjs +11 -0
- package/src/CrossChainState.res +15 -23
- package/src/CrossChainState.res.mjs +10 -18
- package/src/CrossChainState.resi +4 -1
- package/src/Ecosystem.res +7 -2
- package/src/Envio.res +6 -4
- package/src/EventConfigBuilder.res +169 -26
- package/src/EventConfigBuilder.res.mjs +124 -15
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +8 -6
- package/src/HandlerLoader.res +20 -8
- package/src/HandlerLoader.res.mjs +11 -2
- package/src/HandlerRegister.res +21 -4
- package/src/HandlerRegister.res.mjs +24 -5
- package/src/InMemoryStore.res +9 -7
- package/src/InMemoryStore.res.mjs +3 -3
- package/src/IndexerState.res +43 -6
- package/src/IndexerState.res.mjs +36 -7
- package/src/IndexerState.resi +4 -4
- package/src/Internal.res +16 -17
- package/src/Metrics.res +72 -6
- package/src/Metrics.res.mjs +30 -2
- package/src/Persistence.res +36 -30
- package/src/Persistence.res.mjs +1 -20
- package/src/PgStorage.res +104 -56
- package/src/PgStorage.res.mjs +57 -35
- package/src/PruneStaleHistory.res +85 -52
- package/src/PruneStaleHistory.res.mjs +63 -37
- package/src/Rollback.res +68 -45
- package/src/Rollback.res.mjs +38 -19
- package/src/RollbackCommit.res +7 -9
- package/src/RollbackCommit.res.mjs +5 -6
- package/src/SafeCheckpointTracking.res +11 -11
- package/src/SafeCheckpointTracking.res.mjs +7 -6
- package/src/SimulateItems.res +33 -18
- package/src/SimulateItems.res.mjs +26 -22
- package/src/Sink.res +38 -26
- package/src/Sink.res.mjs +21 -16
- package/src/TestIndexer.res +5 -5
- package/src/TestIndexer.res.mjs +1 -1
- package/src/UserContext.res +358 -51
- package/src/UserContext.res.mjs +271 -35
- package/src/Utils.res +170 -0
- package/src/Utils.res.mjs +153 -0
- package/src/Writing.res +2 -2
- package/src/Writing.res.mjs +1 -1
- package/src/bindings/ClickHouse.res +366 -698
- package/src/bindings/ClickHouse.res.mjs +371 -421
- package/src/bindings/ClickHouseSink.res +337 -0
- package/src/bindings/ClickHouseSink.res.mjs +246 -0
- package/src/bindings/EventSource.res +8 -2
- package/src/bindings/NodeJs.res +6 -0
- package/src/bindings/Vitest.res +23 -0
- package/src/bindings/Vitest.res.mjs +3 -0
- package/src/bindings/WebSocket.res +9 -10
- package/src/db/CheckpointBounds.res +53 -0
- package/src/db/CheckpointBounds.res.mjs +44 -0
- package/src/db/EntityFilter.res +36 -17
- package/src/db/EntityFilter.res.mjs +25 -14
- package/src/db/EntityHistory.res +47 -22
- package/src/db/EntityHistory.res.mjs +19 -12
- package/src/db/InternalTable.res +84 -35
- package/src/db/InternalTable.res.mjs +56 -23
- package/src/db/RollbackFloors.res +55 -0
- package/src/db/RollbackFloors.res.mjs +92 -0
- package/src/db/Table.res +22 -4
- package/src/db/Table.res.mjs +30 -9
- package/src/sources/Evm.res +2 -0
- package/src/sources/Evm.res.mjs +2 -0
- package/src/sources/EvmHyperSyncSource.res +3 -3
- package/src/sources/EvmHyperSyncSource.res.mjs +3 -3
- package/src/sources/EvmRpcWs.res +124 -0
- package/src/sources/EvmRpcWs.res.mjs +117 -0
- package/src/sources/Fuel.res +2 -0
- package/src/sources/Fuel.res.mjs +2 -0
- package/src/sources/FuelHyperSyncSource.res +1 -1
- package/src/sources/FuelHyperSyncSource.res.mjs +2 -1
- package/src/sources/HeightFeed.res +568 -0
- package/src/sources/HeightFeed.res.mjs +452 -0
- package/src/sources/HeightStream.res +257 -0
- package/src/sources/HeightStream.res.mjs +194 -0
- package/src/sources/HyperSync.res +5 -0
- package/src/sources/HyperSync.res.mjs +3 -0
- package/src/sources/HyperSync.resi +4 -0
- package/src/sources/HyperSyncSSE.res +49 -0
- package/src/sources/HyperSyncSSE.res.mjs +79 -0
- package/src/sources/RpcSource.res +1 -1
- package/src/sources/RpcSource.res.mjs +2 -2
- package/src/sources/Source.res +54 -1
- package/src/sources/Source.res.mjs +25 -0
- package/src/sources/SourceManager.res +220 -227
- package/src/sources/SourceManager.res.mjs +139 -164
- package/src/sources/SourceManager.resi +8 -0
- package/src/sources/Svm.res +2 -0
- package/src/sources/Svm.res.mjs +2 -0
- package/src/sources/SvmHyperSyncClient.res +70 -127
- package/src/sources/SvmHyperSyncClient.res.mjs +51 -25
- package/src/sources/SvmHyperSyncSource.res +18 -15
- package/src/sources/SvmHyperSyncSource.res.mjs +5 -4
- package/src/subgraph/blocks.ts +176 -0
- package/src/subgraph/calls.ts +217 -0
- package/src/subgraph/conformance.ts +102 -0
- package/src/subgraph/division.ts +133 -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 +1948 -0
- package/src/subgraph/hosts.ts +148 -0
- package/src/subgraph/runtime.ts +863 -0
- package/src/subgraph/scope.ts +66 -0
- package/svm.schema.json +6 -81
- package/src/MemoryStorage.res +0 -729
- package/src/MemoryStorage.res.mjs +0 -586
- package/src/sources/HyperSyncHeightStream.res +0 -129
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -110
- package/src/sources/RpcWebSocketHeightStream.res +0 -175
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -180
package/evm.schema.json
CHANGED
|
@@ -126,6 +126,17 @@
|
|
|
126
126
|
"type": "null"
|
|
127
127
|
}
|
|
128
128
|
]
|
|
129
|
+
},
|
|
130
|
+
"bytes_type": {
|
|
131
|
+
"description": "How the `Bytes` scalar in schema.graphql is represented. `hex` keeps 0x-prefixed hex strings stored as text, `uint8array` exposes `Uint8Array` values in handlers and stores raw bytes (BYTEA in Postgres, String in ClickHouse). (default: hex)",
|
|
132
|
+
"anyOf": [
|
|
133
|
+
{
|
|
134
|
+
"$ref": "#/$defs/BytesType"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"type": "null"
|
|
138
|
+
}
|
|
139
|
+
]
|
|
129
140
|
}
|
|
130
141
|
},
|
|
131
142
|
"additionalProperties": false,
|
|
@@ -758,6 +769,21 @@
|
|
|
758
769
|
"checksum",
|
|
759
770
|
"lowercase"
|
|
760
771
|
]
|
|
772
|
+
},
|
|
773
|
+
"BytesType": {
|
|
774
|
+
"description": "How the schema.graphql `Bytes` scalar reaches handlers and storage.",
|
|
775
|
+
"oneOf": [
|
|
776
|
+
{
|
|
777
|
+
"description": "`0x`-prefixed hex strings, stored as text.",
|
|
778
|
+
"type": "string",
|
|
779
|
+
"const": "hex"
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
"description": "`Uint8Array` values, stored as raw bytes (`BYTEA` in Postgres, `String` in ClickHouse).",
|
|
783
|
+
"type": "string",
|
|
784
|
+
"const": "uint8array"
|
|
785
|
+
}
|
|
786
|
+
]
|
|
761
787
|
}
|
|
762
788
|
}
|
|
763
789
|
}
|
package/fuel.schema.json
CHANGED
|
@@ -83,6 +83,17 @@
|
|
|
83
83
|
"boolean",
|
|
84
84
|
"null"
|
|
85
85
|
]
|
|
86
|
+
},
|
|
87
|
+
"bytes_type": {
|
|
88
|
+
"description": "How the `Bytes` scalar in schema.graphql is represented. `hex` keeps 0x-prefixed hex strings stored as text, `uint8array` exposes `Uint8Array` values in handlers and stores raw bytes (BYTEA in Postgres, String in ClickHouse). (default: hex)",
|
|
89
|
+
"anyOf": [
|
|
90
|
+
{
|
|
91
|
+
"$ref": "#/$defs/BytesType"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"type": "null"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
86
97
|
}
|
|
87
98
|
},
|
|
88
99
|
"additionalProperties": false,
|
|
@@ -464,6 +475,21 @@
|
|
|
464
475
|
}
|
|
465
476
|
}
|
|
466
477
|
]
|
|
478
|
+
},
|
|
479
|
+
"BytesType": {
|
|
480
|
+
"description": "How the schema.graphql `Bytes` scalar reaches handlers and storage.",
|
|
481
|
+
"oneOf": [
|
|
482
|
+
{
|
|
483
|
+
"description": "`0x`-prefixed hex strings, stored as text.",
|
|
484
|
+
"type": "string",
|
|
485
|
+
"const": "hex"
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"description": "`Uint8Array` values, stored as raw bytes (`BYTEA` in Postgres, `String` in ClickHouse).",
|
|
489
|
+
"type": "string",
|
|
490
|
+
"const": "uint8array"
|
|
491
|
+
}
|
|
492
|
+
]
|
|
467
493
|
}
|
|
468
494
|
}
|
|
469
495
|
}
|
package/index.d.ts
CHANGED
|
@@ -1423,7 +1423,7 @@ type SvmSelectedInstruction<Fields extends SvmFieldsSelection, ProgInstr> = {
|
|
|
1423
1423
|
readonly instructionName: string;
|
|
1424
1424
|
readonly discriminator: string;
|
|
1425
1425
|
readonly programId: SvmInstrField<Fields, "programId", string>;
|
|
1426
|
-
readonly data: SvmInstrField<Fields, "data",
|
|
1426
|
+
readonly data: SvmInstrField<Fields, "data", Uint8Array>;
|
|
1427
1427
|
readonly path: SvmInstrField<Fields, "path", readonly number[]>;
|
|
1428
1428
|
readonly isInner: SvmInstrField<Fields, "isInner", boolean>;
|
|
1429
1429
|
readonly args: SvmInstrField<
|
|
@@ -1484,6 +1484,37 @@ export type SvmOnInstructionHandlerArgs<
|
|
|
1484
1484
|
Instruction extends keyof SvmProgramsT[Program] & string = never,
|
|
1485
1485
|
> = SvmOnInstructionArgsFor<SvmInstruction<Fields, Program, Instruction>, GlobalConfig>;
|
|
1486
1486
|
|
|
1487
|
+
/** The named accounts of a configured instruction. Falls back to an open
|
|
1488
|
+
* record when the instruction carries no resolved schema, so its filter keys
|
|
1489
|
+
* are unconstrained rather than unusable. */
|
|
1490
|
+
type SvmAccountsOf<Program extends string, Instruction extends string> =
|
|
1491
|
+
SvmConfiguredInstruction<Program, Instruction>["accounts"];
|
|
1492
|
+
|
|
1493
|
+
/** One AND-group of account narrowings: every named account must match one of
|
|
1494
|
+
* its listed pubkeys. Names are the instruction's own account names. */
|
|
1495
|
+
export type SvmAccountsFilter<Accounts> = {
|
|
1496
|
+
readonly [K in keyof Accounts]?: string | readonly string[];
|
|
1497
|
+
};
|
|
1498
|
+
|
|
1499
|
+
/** The `where` option value of `indexer.onInstruction`.
|
|
1500
|
+
*
|
|
1501
|
+
* `accounts` accepts either a single AND-group of account narrowings, or an
|
|
1502
|
+
* array of them (OR semantics). `block.slot._gte` promotes to the
|
|
1503
|
+
* registration's startBlock and overrides the chain-level `start_block` — use
|
|
1504
|
+
* it to restrict per-instruction processing without touching `config.yaml`.
|
|
1505
|
+
* Only `_gte` is supported here; use `indexer.onSlot` for `_lte` / `_every`. */
|
|
1506
|
+
export type SvmOnInstructionWhere<Accounts> = {
|
|
1507
|
+
/** Match only inner (CPI-invoked) or only outer instructions. Absent
|
|
1508
|
+
* matches both. */
|
|
1509
|
+
readonly isInner?: boolean;
|
|
1510
|
+
readonly accounts?: SvmAccountsFilter<Accounts> | readonly SvmAccountsFilter<Accounts>[];
|
|
1511
|
+
readonly block?: {
|
|
1512
|
+
readonly slot?: {
|
|
1513
|
+
readonly _gte?: number;
|
|
1514
|
+
};
|
|
1515
|
+
};
|
|
1516
|
+
};
|
|
1517
|
+
|
|
1487
1518
|
/** Options for an SVM `indexer.onInstruction` registration. */
|
|
1488
1519
|
export type SvmOnInstructionOptions<
|
|
1489
1520
|
P extends string = string,
|
|
@@ -1493,10 +1524,11 @@ export type SvmOnInstructionOptions<
|
|
|
1493
1524
|
/** Program name as declared under `chains[].programs[].name` in
|
|
1494
1525
|
* `config.yaml`. */
|
|
1495
1526
|
readonly program: P;
|
|
1496
|
-
/** Instruction name
|
|
1497
|
-
* `chains[].programs[].instructions[].name`
|
|
1527
|
+
/** Instruction name from the program's IDL, or from
|
|
1528
|
+
* `chains[].programs[].instructions[].name` when the layout is inline. */
|
|
1498
1529
|
readonly instruction: I;
|
|
1499
1530
|
readonly fields?: Fields & SvmFieldsLiteralCheck<Fields>;
|
|
1531
|
+
readonly where?: SvmOnInstructionWhere<SvmAccountsOf<P, I>>;
|
|
1500
1532
|
};
|
|
1501
1533
|
|
|
1502
1534
|
/** Handler function for an SVM `indexer.onInstruction` registration. Takes
|
|
@@ -1736,9 +1768,10 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
|
|
|
1736
1768
|
}
|
|
1737
1769
|
? {
|
|
1738
1770
|
/**
|
|
1739
|
-
* Register an instruction handler.
|
|
1740
|
-
*
|
|
1741
|
-
* Handler `fields` is the only
|
|
1771
|
+
* Register an instruction handler. `program` and `instruction`
|
|
1772
|
+
* name an entry from the IDL or YAML. Dispatch uses that
|
|
1773
|
+
* instruction's discriminator. Handler `fields` is the only
|
|
1774
|
+
* source of payload selection.
|
|
1742
1775
|
*/
|
|
1743
1776
|
readonly onInstruction: <
|
|
1744
1777
|
P extends keyof Programs & string,
|
|
@@ -1905,8 +1938,8 @@ type SvmSimulateItem<Config extends IndexerConfigTypes = GlobalConfig> =
|
|
|
1905
1938
|
path?: readonly number[];
|
|
1906
1939
|
/** Override the program id. Defaults to the configured `program_id`. */
|
|
1907
1940
|
programId?: string;
|
|
1908
|
-
/** Raw instruction data
|
|
1909
|
-
data?:
|
|
1941
|
+
/** Raw instruction data. Defaults to the configured discriminator bytes. */
|
|
1942
|
+
data?: Uint8Array;
|
|
1910
1943
|
/** Whether this is a CPI-invoked inner instruction. */
|
|
1911
1944
|
isInner?: boolean;
|
|
1912
1945
|
/** Decoded args. Keys match the instruction's arg names. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0-subgraph",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
|
|
6
6
|
"bin": "./bin.mjs",
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
"licenses"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@clickhouse/client": "1.17.0",
|
|
45
44
|
"@elastic/ecs-pino-format": "1.4.0",
|
|
46
45
|
"@fuel-ts/crypto": "0.96.1",
|
|
47
46
|
"@fuel-ts/errors": "0.96.1",
|
|
@@ -69,10 +68,10 @@
|
|
|
69
68
|
"tsx": "4.21.0"
|
|
70
69
|
},
|
|
71
70
|
"optionalDependencies": {
|
|
72
|
-
"envio-linux-x64": "3.
|
|
73
|
-
"envio-linux-x64-musl": "3.
|
|
74
|
-
"envio-linux-arm64": "3.
|
|
75
|
-
"envio-darwin-x64": "3.
|
|
76
|
-
"envio-darwin-arm64": "3.
|
|
71
|
+
"envio-linux-x64": "3.10.0-subgraph",
|
|
72
|
+
"envio-linux-x64-musl": "3.10.0-subgraph",
|
|
73
|
+
"envio-linux-arm64": "3.10.0-subgraph",
|
|
74
|
+
"envio-darwin-x64": "3.10.0-subgraph",
|
|
75
|
+
"envio-darwin-arm64": "3.10.0-subgraph"
|
|
77
76
|
}
|
|
78
77
|
}
|
package/src/Batch.res
CHANGED
|
@@ -189,6 +189,15 @@ let addReorgCheckpoints = (
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
// Checkpoint ids are handed out in ascending order as each chain's items are
|
|
193
|
+
// walked in block order, so within a chain a higher id always means a later
|
|
194
|
+
// block. Rollback preserves that: it deletes the chain's ids above its target
|
|
195
|
+
// before any higher one is allocated, so the ids the re-indexed blocks get are
|
|
196
|
+
// above everything the chain still holds. An isolated rollback leans on the
|
|
197
|
+
// invariant — it deletes by `chain_id = c AND id > target`, which is only the
|
|
198
|
+
// chain's stale suffix if ids and blocks agree on order within the chain. Ids
|
|
199
|
+
// interleave freely *across* chains, which is exactly why that predicate can't
|
|
200
|
+
// be the id bound alone.
|
|
192
201
|
let prepareBatch = (
|
|
193
202
|
~checkpointIdBeforeBatch,
|
|
194
203
|
~chainsBeforeBatch: dict<chainBeforeBatch>,
|
package/src/ChainState.res
CHANGED
|
@@ -310,7 +310,11 @@ let makeInternal = (
|
|
|
310
310
|
chainId,
|
|
311
311
|
endpointUrl: hypersyncUrl,
|
|
312
312
|
apiToken,
|
|
313
|
-
onEventRegistrations
|
|
313
|
+
onEventRegistrations: onEventRegistrations->(
|
|
314
|
+
Utils.magic: array<Internal.onEventRegistration> => array<
|
|
315
|
+
Internal.svmOnEventRegistration,
|
|
316
|
+
>
|
|
317
|
+
),
|
|
314
318
|
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
|
|
315
319
|
addressStore,
|
|
316
320
|
}),
|
|
@@ -1205,21 +1209,17 @@ let markReady = (cs: t, ~readyAt) =>
|
|
|
1205
1209
|
cs.timestampCaughtUpToHeadOrEndblock = Some(readyAt)
|
|
1206
1210
|
}
|
|
1207
1211
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
//
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
~eventsProcessedDiff,
|
|
1220
|
-
~rollbackTargetBlockNumber,
|
|
1221
|
-
~isReorgChain,
|
|
1222
|
-
): array<AddressRows.key> => {
|
|
1212
|
+
type progressDiff = {blockNumber: int, eventsProcessed: float}
|
|
1213
|
+
|
|
1214
|
+
type rolledBackTo =
|
|
1215
|
+
| RecomputedProgress(progressDiff)
|
|
1216
|
+
| ForkBlock(int)
|
|
1217
|
+
| Untouched
|
|
1218
|
+
|
|
1219
|
+
// Returns the address registrations the storage has to delete along with the
|
|
1220
|
+
// chain — the store is what decides which ones died, so the two halves of a
|
|
1221
|
+
// rollback can't disagree.
|
|
1222
|
+
let rollback = (cs: t, ~rolledBackTo: rolledBackTo): array<AddressRows.key> => {
|
|
1223
1223
|
let rollbackTo = targetBlockNumber => {
|
|
1224
1224
|
let {fetchState, rolledBackAddresses} =
|
|
1225
1225
|
cs.fetchState->FetchState.rollback(
|
|
@@ -1234,15 +1234,15 @@ let rollback = (
|
|
|
1234
1234
|
})
|
|
1235
1235
|
}
|
|
1236
1236
|
|
|
1237
|
-
switch
|
|
1238
|
-
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1237
|
+
switch rolledBackTo {
|
|
1238
|
+
| RecomputedProgress({blockNumber, eventsProcessed}) =>
|
|
1239
|
+
// A rollback only ever takes a chain back. The diff recomputes progress from
|
|
1240
|
+
// the checkpoints still in the database, so a chain that an unwritten
|
|
1241
|
+
// rollback already took below them — to a fork block only that rollback
|
|
1242
|
+
// knew — would be handed their MIN back and moved forward onto blocks it
|
|
1243
|
+
// never re-indexed.
|
|
1244
|
+
let newProgressBlockNumber = Pervasives.min(blockNumber, cs.committedProgressBlockNumber)
|
|
1245
|
+
let newTotalEventsProcessed = cs.numEventsProcessed -. eventsProcessed
|
|
1246
1246
|
|
|
1247
1247
|
switch cs.safeCheckpointTracking {
|
|
1248
1248
|
| Some(safeCheckpointTracking) =>
|
|
@@ -1260,19 +1260,15 @@ let rollback = (
|
|
|
1260
1260
|
cs.processingBlockNumber = newProgressBlockNumber
|
|
1261
1261
|
cs.numEventsProcessed = newTotalEventsProcessed
|
|
1262
1262
|
rolledBackAddresses
|
|
1263
|
-
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
rolledBackAddresses
|
|
1274
|
-
} else {
|
|
1275
|
-
[]
|
|
1276
|
-
}
|
|
1263
|
+
| ForkBlock(forkBlock) =>
|
|
1264
|
+
// Rewinds the stores too, not just progress: otherwise the stale block hash
|
|
1265
|
+
// survives and re-triggers the same reorg.
|
|
1266
|
+
let rolledBackAddresses = rollbackTo(forkBlock)
|
|
1267
|
+
cs.transactionStore->TransactionStore.rollback(forkBlock)
|
|
1268
|
+
cs.blockStore->BlockStore.rollback(forkBlock)
|
|
1269
|
+
cs.committedProgressBlockNumber = Pervasives.min(cs.committedProgressBlockNumber, forkBlock)
|
|
1270
|
+
cs.processingBlockNumber = Pervasives.min(cs.processingBlockNumber, forkBlock)
|
|
1271
|
+
rolledBackAddresses
|
|
1272
|
+
| Untouched => []
|
|
1277
1273
|
}
|
|
1278
1274
|
}
|
package/src/ChainState.res.mjs
CHANGED
|
@@ -857,7 +857,7 @@ function markReady(cs, readyAt) {
|
|
|
857
857
|
}
|
|
858
858
|
}
|
|
859
859
|
|
|
860
|
-
function rollback(cs,
|
|
860
|
+
function rollback(cs, rolledBackTo) {
|
|
861
861
|
let rollbackTo = targetBlockNumber => {
|
|
862
862
|
let match = FetchState.rollback(cs.fetchState, cs.addressStore, targetBlockNumber);
|
|
863
863
|
cs.fetchState = match.fetchState;
|
|
@@ -867,8 +867,13 @@ function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTarge
|
|
|
867
867
|
contractId: param.contractId
|
|
868
868
|
}));
|
|
869
869
|
};
|
|
870
|
-
if (
|
|
871
|
-
|
|
870
|
+
if (typeof rolledBackTo !== "object") {
|
|
871
|
+
return [];
|
|
872
|
+
}
|
|
873
|
+
if (rolledBackTo.TAG === "RecomputedProgress") {
|
|
874
|
+
let match = rolledBackTo._0;
|
|
875
|
+
let newProgressBlockNumber = Primitive_int.min(match.blockNumber, cs.committedProgressBlockNumber);
|
|
876
|
+
let newTotalEventsProcessed = cs.numEventsProcessed - match.eventsProcessed;
|
|
872
877
|
let safeCheckpointTracking = cs.safeCheckpointTracking;
|
|
873
878
|
if (safeCheckpointTracking !== undefined) {
|
|
874
879
|
cs.safeCheckpointTracking = SafeCheckpointTracking.rollback(safeCheckpointTracking, newProgressBlockNumber);
|
|
@@ -881,14 +886,12 @@ function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTarge
|
|
|
881
886
|
cs.numEventsProcessed = newTotalEventsProcessed;
|
|
882
887
|
return rolledBackAddresses;
|
|
883
888
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
cs.
|
|
889
|
-
cs.
|
|
890
|
-
cs.committedProgressBlockNumber = Primitive_int.min(cs.committedProgressBlockNumber, rollbackTargetBlockNumber);
|
|
891
|
-
cs.processingBlockNumber = Primitive_int.min(cs.processingBlockNumber, rollbackTargetBlockNumber);
|
|
889
|
+
let forkBlock = rolledBackTo._0;
|
|
890
|
+
let rolledBackAddresses$1 = rollbackTo(forkBlock);
|
|
891
|
+
cs.transactionStore.rollback(forkBlock);
|
|
892
|
+
cs.blockStore.rollback(forkBlock);
|
|
893
|
+
cs.committedProgressBlockNumber = Primitive_int.min(cs.committedProgressBlockNumber, forkBlock);
|
|
894
|
+
cs.processingBlockNumber = Primitive_int.min(cs.processingBlockNumber, forkBlock);
|
|
892
895
|
return rolledBackAddresses$1;
|
|
893
896
|
}
|
|
894
897
|
|
package/src/ChainState.resi
CHANGED
|
@@ -157,10 +157,18 @@ let enterReorgThreshold: t => unit
|
|
|
157
157
|
let advanceAfterBatch: (t, ~batch: Batch.t, ~enteringReorgThreshold: bool) => unit
|
|
158
158
|
let applyBatchProgress: (t, ~batch: Batch.t, ~blockTimestampName: string) => unit
|
|
159
159
|
let markReady: (t, ~readyAt: Date.t) => unit
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
160
|
+
// What a rollback's progress diff says about one chain: the block its surviving
|
|
161
|
+
// checkpoints put it back to, and the events the deleted ones carried away. One
|
|
162
|
+
// record because one diff row yields both — they are never known separately.
|
|
163
|
+
type progressDiff = {blockNumber: int, eventsProcessed: float}
|
|
164
|
+
|
|
165
|
+
// Where a rollback leaves one chain.
|
|
166
|
+
type rolledBackTo =
|
|
167
|
+
| RecomputedProgress(progressDiff)
|
|
168
|
+
// The reorg chain with no checkpoint left at or below the target, so only the
|
|
169
|
+
// fork block says where it goes.
|
|
170
|
+
| ForkBlock(int)
|
|
171
|
+
// A chain this rollback doesn't reach.
|
|
172
|
+
| Untouched
|
|
173
|
+
|
|
174
|
+
let rollback: (t, ~rolledBackTo: rolledBackTo) => array<AddressRows.key>
|
package/src/Config.res
CHANGED
|
@@ -127,6 +127,9 @@ type t = {
|
|
|
127
127
|
userEntitiesByName: dict<Internal.entityConfig>,
|
|
128
128
|
userEntities: array<Internal.entityConfig>,
|
|
129
129
|
allEnums: array<Table.enumConfig<Table.enum>>,
|
|
130
|
+
// Set only in subgraph mode: the translated manifest, which is what makes
|
|
131
|
+
// the subgraph runtime take over handler registration.
|
|
132
|
+
subgraph: option<JSON.t>,
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
type rpcSourceFor = | @as("sync") Sync | @as("fallback") Fallback | @as("realtime") Realtime
|
|
@@ -177,24 +180,6 @@ let publicConfigChainSchema = S.schema(s =>
|
|
|
177
180
|
let svmEventDescriptorSchema = S.schema(s =>
|
|
178
181
|
{
|
|
179
182
|
"discriminator": s.matches(S.option(S.string)),
|
|
180
|
-
"discriminatorByteLen": s.matches(S.int),
|
|
181
|
-
// An array of AND-groups OR-ed together: the CLI normalizes both the flat
|
|
182
|
-
// and `any_of` YAML shapes to `Vec<Vec<SvmAccountFilterJson>>`.
|
|
183
|
-
"accountFilters": s.matches(
|
|
184
|
-
S.option(
|
|
185
|
-
S.array(
|
|
186
|
-
S.array(
|
|
187
|
-
S.schema(s =>
|
|
188
|
-
{
|
|
189
|
-
"position": s.matches(S.int),
|
|
190
|
-
"values": s.matches(S.array(S.string)),
|
|
191
|
-
}
|
|
192
|
-
),
|
|
193
|
-
),
|
|
194
|
-
),
|
|
195
|
-
),
|
|
196
|
-
),
|
|
197
|
-
"isInner": s.matches(S.option(S.bool)),
|
|
198
183
|
"accounts": s.matches(S.option(S.array(S.string))),
|
|
199
184
|
"args": s.matches(S.option(S.json(~validate=false))),
|
|
200
185
|
}
|
|
@@ -341,6 +326,7 @@ let getFieldTypeAndSchema = (prop, ~enumConfigsByName: dict<Table.enumConfig<Tab
|
|
|
341
326
|
|
|
342
327
|
let (fieldType, baseSchema) = switch typ {
|
|
343
328
|
| "string" => (Table.String, S.string->S.toUnknown)
|
|
329
|
+
| "bytes" => (Table.Bytea, Utils.Schema.bytes->S.toUnknown)
|
|
344
330
|
| "boolean" => (Table.Boolean, S.bool->S.toUnknown)
|
|
345
331
|
| "int" => (Table.Int32, S.int->S.toUnknown)
|
|
346
332
|
| "bigint" => (Table.BigInt({precision: ?prop["precision"]}), Utils.BigInt.schema->S.toUnknown)
|
|
@@ -374,13 +360,13 @@ let getFieldTypeAndSchema = (prop, ~enumConfigsByName: dict<Table.enumConfig<Tab
|
|
|
374
360
|
| other => JsError.throwWithMessage("Unknown field type in entity config: " ++ other)
|
|
375
361
|
}
|
|
376
362
|
|
|
377
|
-
let fieldSchema =
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
363
|
+
let fieldSchema = switch (fieldType, isArray) {
|
|
364
|
+
| (Table.Bytea, true) => Utils.Schema.bytesArray->S.toUnknown
|
|
365
|
+
| (_, true) => S.array(baseSchema)->S.toUnknown
|
|
366
|
+
| (_, false) => baseSchema
|
|
381
367
|
}
|
|
382
368
|
let fieldSchema = if isNullable {
|
|
383
|
-
|
|
369
|
+
Utils.Schema.nullTolerant(fieldSchema)->S.toUnknown
|
|
384
370
|
} else {
|
|
385
371
|
fieldSchema
|
|
386
372
|
}
|
|
@@ -563,6 +549,7 @@ let publicConfigSchema = S.schema(s =>
|
|
|
563
549
|
"svm": s.matches(S.option(publicConfigEcosystemSchema)),
|
|
564
550
|
"enums": s.matches(S.option(S.dict(S.array(S.string)))),
|
|
565
551
|
"entities": s.matches(S.option(S.array(entityJsonSchema))),
|
|
552
|
+
"subgraph": s.matches(S.option(S.json(~validate=false))),
|
|
566
553
|
}
|
|
567
554
|
)
|
|
568
555
|
|
|
@@ -753,11 +740,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
753
740
|
Utils.magic: _ => {
|
|
754
741
|
"svm": option<{
|
|
755
742
|
"discriminator": option<string>,
|
|
756
|
-
"discriminatorByteLen": int,
|
|
757
|
-
"accountFilters": option<
|
|
758
|
-
array<array<{"position": int, "values": array<string>}>>,
|
|
759
|
-
>,
|
|
760
|
-
"isInner": option<bool>,
|
|
761
743
|
"accounts": option<array<string>>,
|
|
762
744
|
"args": option<JSON.t>,
|
|
763
745
|
}>,
|
|
@@ -770,25 +752,11 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
770
752
|
`SVM instruction ${contractName}.${eventName} is missing the "svm" descriptor in internal config`,
|
|
771
753
|
)
|
|
772
754
|
}
|
|
773
|
-
let accountFilters =
|
|
774
|
-
svm["accountFilters"]
|
|
775
|
-
->Option.getOr([])
|
|
776
|
-
->Array.map(group =>
|
|
777
|
-
group->Array.map(
|
|
778
|
-
af => {
|
|
779
|
-
Internal.position: af["position"],
|
|
780
|
-
values: af["values"]->SvmTypes.Pubkey.fromStringsUnsafe,
|
|
781
|
-
},
|
|
782
|
-
)
|
|
783
|
-
)
|
|
784
755
|
(EventConfigBuilder.buildSvmInstructionEventConfig(
|
|
785
756
|
~contractName,
|
|
786
757
|
~instructionName=eventName,
|
|
787
758
|
~programId,
|
|
788
759
|
~discriminator=svm["discriminator"],
|
|
789
|
-
~discriminatorByteLen=svm["discriminatorByteLen"],
|
|
790
|
-
~accountFilters,
|
|
791
|
-
~isInner=svm["isInner"],
|
|
792
760
|
~accounts=svm["accounts"]->Option.getOr([]),
|
|
793
761
|
~args=svm["args"]->Option.getOr(JSON.Null),
|
|
794
762
|
~definedTypes=svmDefinedTypes,
|
|
@@ -1067,9 +1035,18 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
1067
1035
|
userEntitiesByName,
|
|
1068
1036
|
userEntities,
|
|
1069
1037
|
allEnums,
|
|
1038
|
+
subgraph: publicConfig["subgraph"],
|
|
1070
1039
|
}
|
|
1071
1040
|
}
|
|
1072
1041
|
|
|
1042
|
+
// With no cross-chain entity, a reorg on one chain can never have changed a row
|
|
1043
|
+
// another chain owns, so its rollback stays isolated to that chain instead of
|
|
1044
|
+
// dragging every sibling back with it. A single chain has no sibling to spare,
|
|
1045
|
+
// and narrowing its rollback would only buy it a predicate that always holds.
|
|
1046
|
+
let isIsolatedMultichain = (config: t) =>
|
|
1047
|
+
config.chainMap->ChainMap.keys->Array.length > 1 &&
|
|
1048
|
+
config.userEntities->Array.every(entityConfig => !entityConfig.crossChain)
|
|
1049
|
+
|
|
1073
1050
|
// Canonicalize a user-provided address to the configured casing so it matches
|
|
1074
1051
|
// addresses parsed from config.yaml during routing. HyperSync/RPC data arrives
|
|
1075
1052
|
// already canonical; only user-land input (simulate srcAddress, contractRegister
|
|
@@ -1141,8 +1118,17 @@ let getEventConfig = (config: t, ~contractName, ~eventName, ~chainId: option<Cha
|
|
|
1141
1118
|
})
|
|
1142
1119
|
}
|
|
1143
1120
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1121
|
+
// A chain that can't be rolled back (maxReorgDepth = 0) has no history to keep,
|
|
1122
|
+
// unless a cross-chain entity lets another chain's rollback reach its rows.
|
|
1123
|
+
let shouldSaveHistory = (config, ~isInReorgThreshold, ~chainId: option<ChainId.t>=?) =>
|
|
1124
|
+
config.shouldSaveFullHistory ||
|
|
1125
|
+
(config.shouldRollbackOnReorg &&
|
|
1126
|
+
isInReorgThreshold &&
|
|
1127
|
+
switch chainId {
|
|
1128
|
+
| Some(chainId) if config->isIsolatedMultichain =>
|
|
1129
|
+
(config.chainMap->ChainMap.get(chainId)).maxReorgDepth > 0
|
|
1130
|
+
| _ => true
|
|
1131
|
+
})
|
|
1146
1132
|
|
|
1147
1133
|
let shouldPruneHistory = (config, ~isInReorgThreshold) =>
|
|
1148
1134
|
!config.shouldSaveFullHistory && (config.shouldRollbackOnReorg && isInReorgThreshold)
|
|
@@ -1203,6 +1189,10 @@ let stripSensitiveData = (json: JSON.t): JSON.t => {
|
|
|
1203
1189
|
stripChains(obj->Dict.get("evm"))
|
|
1204
1190
|
stripChains(obj->Dict.get("fuel"))
|
|
1205
1191
|
stripChains(obj->Dict.get("svm"))
|
|
1192
|
+
// The subgraph blob is how the runtime finds mappings. None of it
|
|
1193
|
+
// describes stored data — that's already in `evm` / `entities` — so a
|
|
1194
|
+
// specVersion bump or a mapping-path edit must not force a reset.
|
|
1195
|
+
obj->Utils.Dict.deleteInPlace("subgraph")
|
|
1206
1196
|
}
|
|
1207
1197
|
| _ => ()
|
|
1208
1198
|
}
|
|
@@ -1362,6 +1352,33 @@ let throwIfIncompatible = (
|
|
|
1362
1352
|
}
|
|
1363
1353
|
}
|
|
1364
1354
|
|
|
1355
|
+
let throwIfResumeIncompatible = (
|
|
1356
|
+
~storedEnvioInfo: option<JSON.t>,
|
|
1357
|
+
~storedContractMapping: ContractMapping.t,
|
|
1358
|
+
~envioInfo: JSON.t,
|
|
1359
|
+
~contractMapping: ContractMapping.t,
|
|
1360
|
+
~resetCommand: string,
|
|
1361
|
+
~runCommand: option<string>,
|
|
1362
|
+
) => {
|
|
1363
|
+
let changedPaths = switch storedEnvioInfo {
|
|
1364
|
+
| None => ["storage was initialized by an older envio version"]
|
|
1365
|
+
| Some(stored) => diffPaths(~stored, ~current=envioInfo)
|
|
1366
|
+
}
|
|
1367
|
+
let changedPaths =
|
|
1368
|
+
storedContractMapping->ContractMapping.isEqual(contractMapping)
|
|
1369
|
+
? changedPaths
|
|
1370
|
+
: changedPaths->Array.concat(["contracts"])
|
|
1371
|
+
let hasClickhouse = switch envioInfo {
|
|
1372
|
+
| Object(d) =>
|
|
1373
|
+
switch d->Dict.get("storage") {
|
|
1374
|
+
| Some(Object(s)) => s->Dict.get("clickhouse") == Some(Boolean(true))
|
|
1375
|
+
| _ => false
|
|
1376
|
+
}
|
|
1377
|
+
| _ => false
|
|
1378
|
+
}
|
|
1379
|
+
throwIfIncompatible(changedPaths, ~resetCommand, ~runCommand, ~hasClickhouse)
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1365
1382
|
// The returned value is a pure function of the JSON: it holds only event
|
|
1366
1383
|
// definitions, never handler/contractRegister/where state (that's layered on
|
|
1367
1384
|
// separately as `HandlerRegister.registrationsByChainId`). That purity is
|