envio 3.0.2 → 3.1.0-rc.0
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/README.md +0 -1
- package/evm.schema.json +15 -8
- package/fuel.schema.json +19 -12
- package/index.d.ts +0 -2
- package/package.json +6 -7
- package/rescript.json +1 -1
- package/src/Batch.res +4 -214
- package/src/Batch.res.mjs +6 -165
- package/src/ChainFetcher.res +4 -5
- package/src/ChainFetcher.res.mjs +6 -7
- package/src/ChainManager.res +10 -9
- package/src/ChainManager.res.mjs +6 -10
- package/src/Config.res +9 -25
- package/src/Config.res.mjs +17 -27
- package/src/Core.res +7 -0
- package/src/Ctx.res +1 -0
- package/src/Env.res +0 -1
- package/src/Env.res.mjs +0 -3
- package/src/EventConfigBuilder.res +13 -123
- package/src/EventConfigBuilder.res.mjs +6 -73
- package/src/EventProcessing.res +5 -29
- package/src/EventProcessing.res.mjs +11 -20
- package/src/EventUtils.res +0 -27
- package/src/EventUtils.res.mjs +0 -24
- package/src/FetchState.res +1 -11
- package/src/FetchState.res.mjs +2 -16
- package/src/GlobalState.res +23 -37
- package/src/GlobalState.res.mjs +10 -38
- package/src/HandlerLoader.res +6 -5
- package/src/HandlerLoader.res.mjs +27 -9
- package/src/HandlerRegister.res +1 -12
- package/src/HandlerRegister.res.mjs +1 -6
- package/src/HandlerRegister.resi +1 -1
- package/src/Hasura.res +96 -32
- package/src/Hasura.res.mjs +93 -38
- package/src/InMemoryStore.res +181 -45
- package/src/InMemoryStore.res.mjs +143 -40
- package/src/InMemoryTable.res +147 -247
- package/src/InMemoryTable.res.mjs +131 -230
- package/src/Internal.res +10 -34
- package/src/Internal.res.mjs +9 -3
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +5 -5
- package/src/Main.res +4 -6
- package/src/Main.res.mjs +26 -15
- package/src/Persistence.res +7 -132
- package/src/Persistence.res.mjs +1 -102
- package/src/PgStorage.res +57 -40
- package/src/PgStorage.res.mjs +60 -34
- package/src/ReorgDetection.res +35 -58
- package/src/ReorgDetection.res.mjs +21 -29
- package/src/SimulateItems.res.mjs +21 -3
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +1 -1
- package/src/TableIndices.res +9 -2
- package/src/TableIndices.res.mjs +7 -1
- package/src/TestIndexer.res +53 -60
- package/src/TestIndexer.res.mjs +77 -63
- package/src/TestIndexerProxyStorage.res +4 -14
- package/src/TestIndexerProxyStorage.res.mjs +1 -5
- package/src/UserContext.res +2 -4
- package/src/UserContext.res.mjs +4 -5
- package/src/Utils.res +0 -2
- package/src/Utils.res.mjs +0 -3
- package/src/bindings/ClickHouse.res +45 -38
- package/src/bindings/ClickHouse.res.mjs +16 -17
- package/src/bindings/Vitest.res +3 -0
- package/src/db/InternalTable.res +59 -18
- package/src/db/InternalTable.res.mjs +82 -51
- package/src/db/Table.res +9 -2
- package/src/db/Table.res.mjs +10 -7
- package/src/sources/EvmChain.res +32 -9
- package/src/sources/EvmChain.res.mjs +31 -4
- package/src/sources/HyperFuelSource.res +14 -57
- package/src/sources/HyperFuelSource.res.mjs +18 -38
- package/src/sources/HyperSync.res +36 -101
- package/src/sources/HyperSync.res.mjs +42 -96
- package/src/sources/HyperSync.resi +4 -22
- package/src/sources/HyperSyncClient.res +67 -245
- package/src/sources/HyperSyncClient.res.mjs +47 -46
- package/src/sources/HyperSyncSource.res +76 -147
- package/src/sources/HyperSyncSource.res.mjs +61 -114
- package/src/sources/RpcSource.res +43 -22
- package/src/sources/RpcSource.res.mjs +50 -35
- package/src/sources/SimulateSource.res +1 -7
- package/src/sources/SimulateSource.res.mjs +1 -7
- package/src/sources/Source.res +8 -1
- package/src/sources/SourceManager.res +9 -0
- package/src/sources/SourceManager.res.mjs +10 -0
- package/src/sources/SourceManager.resi +2 -0
- package/svm.schema.json +11 -4
|
@@ -7,6 +7,7 @@ type blockInfo = {
|
|
|
7
7
|
number: int,
|
|
8
8
|
timestamp: int,
|
|
9
9
|
hash: string,
|
|
10
|
+
parentHash: string,
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
let getKnownRawBlock = async (~client, ~blockNumber) =>
|
|
@@ -29,6 +30,9 @@ let parseBlockInfo = (json: JSON.t): blockInfo => {
|
|
|
29
30
|
hash: jsonDict
|
|
30
31
|
->Dict.getUnsafe("hash")
|
|
31
32
|
->S.parseOrThrow(S.string),
|
|
33
|
+
parentHash: jsonDict
|
|
34
|
+
->Dict.getUnsafe("parentHash")
|
|
35
|
+
->S.parseOrThrow(S.string),
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
@@ -838,7 +842,7 @@ type options = {
|
|
|
838
842
|
url: string,
|
|
839
843
|
chain: ChainMap.Chain.t,
|
|
840
844
|
eventRouter: EventRouter.t<Internal.evmEventConfig>,
|
|
841
|
-
|
|
845
|
+
allEventParams: array<HyperSyncClient.Decoder.eventParamsInput>,
|
|
842
846
|
lowercaseAddresses: bool,
|
|
843
847
|
ws?: string,
|
|
844
848
|
}
|
|
@@ -850,7 +854,7 @@ let make = (
|
|
|
850
854
|
url,
|
|
851
855
|
chain,
|
|
852
856
|
eventRouter,
|
|
853
|
-
|
|
857
|
+
allEventParams,
|
|
854
858
|
lowercaseAddresses,
|
|
855
859
|
?ws,
|
|
856
860
|
}: options,
|
|
@@ -993,12 +997,16 @@ let make = (
|
|
|
993
997
|
{log: hyperSyncLog}
|
|
994
998
|
}
|
|
995
999
|
|
|
996
|
-
let hscDecoder: ref<option<HyperSyncClient.Decoder.
|
|
1000
|
+
let hscDecoder: ref<option<HyperSyncClient.Decoder.tWithParams>> = ref(None)
|
|
997
1001
|
let getHscDecoder = () => {
|
|
998
1002
|
switch hscDecoder.contents {
|
|
999
1003
|
| Some(decoder) => decoder
|
|
1000
1004
|
| None => {
|
|
1001
|
-
let decoder = HyperSyncClient.Decoder.
|
|
1005
|
+
let decoder = HyperSyncClient.Decoder.fromParams(
|
|
1006
|
+
allEventParams,
|
|
1007
|
+
~checksumAddresses=!lowercaseAddresses,
|
|
1008
|
+
)
|
|
1009
|
+
hscDecoder := Some(decoder)
|
|
1002
1010
|
decoder
|
|
1003
1011
|
}
|
|
1004
1012
|
}
|
|
@@ -1071,7 +1079,7 @@ let make = (
|
|
|
1071
1079
|
// We also don't care about it when we have a hard max block interval
|
|
1072
1080
|
if (
|
|
1073
1081
|
executedBlockInterval >= suggestedBlockInterval &&
|
|
1074
|
-
!(mutSuggestedBlockIntervals->
|
|
1082
|
+
!(mutSuggestedBlockIntervals->Dict.has(maxSuggestedBlockIntervalKey))
|
|
1075
1083
|
) {
|
|
1076
1084
|
// Increase batch size going forward, but do not increase past a configured maximum
|
|
1077
1085
|
// See: https://en.wikipedia.org/wiki/Additive_increase/multiplicative_decrease
|
|
@@ -1088,7 +1096,7 @@ let make = (
|
|
|
1088
1096
|
let hyperSyncEvents = logs->Belt.Array.map(convertLogToHyperSyncEvent)
|
|
1089
1097
|
|
|
1090
1098
|
// Decode using HyperSyncClient decoder
|
|
1091
|
-
let parsedEvents = try await getHscDecoder().
|
|
1099
|
+
let parsedEvents = try await getHscDecoder().decodeLogs(hyperSyncEvents) catch {
|
|
1092
1100
|
| exn =>
|
|
1093
1101
|
throw(
|
|
1094
1102
|
Source.GetItemsError(
|
|
@@ -1107,7 +1115,7 @@ let make = (
|
|
|
1107
1115
|
->Array.zip(parsedEvents)
|
|
1108
1116
|
->Array.filterMap(((
|
|
1109
1117
|
log: Rpc.GetLogs.log,
|
|
1110
|
-
maybeDecodedEvent: Nullable.t<
|
|
1118
|
+
maybeDecodedEvent: Nullable.t<Internal.eventParams>,
|
|
1111
1119
|
)) => {
|
|
1112
1120
|
let topic0 = log.topics[0]->Option.getOr("0x0")
|
|
1113
1121
|
let routedAddress = if lowercaseAddresses {
|
|
@@ -1158,7 +1166,7 @@ let make = (
|
|
|
1158
1166
|
contractName: eventConfig.contractName,
|
|
1159
1167
|
eventName: eventConfig.name,
|
|
1160
1168
|
chainId: chain->ChainMap.Chain.toChainId,
|
|
1161
|
-
params: decoded
|
|
1169
|
+
params: decoded,
|
|
1162
1170
|
transaction,
|
|
1163
1171
|
block,
|
|
1164
1172
|
srcAddress: routedAddress,
|
|
@@ -1178,16 +1186,27 @@ let make = (
|
|
|
1178
1186
|
|
|
1179
1187
|
let totalTimeElapsed = startFetchingBatchTimeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
|
|
1180
1188
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
})
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
blockHash:
|
|
1189
|
-
|
|
1189
|
+
// Every fetched block carries `hash` and `parentHash`, so each one yields
|
|
1190
|
+
// two confirmed (number, hash) pairs for reorg detection at no extra cost.
|
|
1191
|
+
let blockHashes = []
|
|
1192
|
+
let pushBlockInfo = (b: blockInfo) => {
|
|
1193
|
+
blockHashes->Array.push({ReorgDetection.blockNumber: b.number, blockHash: b.hash})->ignore
|
|
1194
|
+
if b.number > 0 {
|
|
1195
|
+
blockHashes
|
|
1196
|
+
->Array.push({ReorgDetection.blockNumber: b.number - 1, blockHash: b.parentHash})
|
|
1197
|
+
->ignore
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
pushBlockInfo(latestFetchedBlockInfo)
|
|
1201
|
+
switch optFirstBlockParent {
|
|
1202
|
+
| Some(b) => pushBlockInfo(b)
|
|
1203
|
+
| None => ()
|
|
1190
1204
|
}
|
|
1205
|
+
logs->Belt.Array.forEach(log =>
|
|
1206
|
+
blockHashes
|
|
1207
|
+
->Array.push({ReorgDetection.blockNumber: log.blockNumber, blockHash: log.blockHash})
|
|
1208
|
+
->ignore
|
|
1209
|
+
)
|
|
1191
1210
|
|
|
1192
1211
|
{
|
|
1193
1212
|
latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
|
|
@@ -1197,19 +1216,20 @@ let make = (
|
|
|
1197
1216
|
totalTimeElapsed: totalTimeElapsed,
|
|
1198
1217
|
},
|
|
1199
1218
|
knownHeight,
|
|
1200
|
-
|
|
1219
|
+
blockHashes,
|
|
1201
1220
|
fromBlockQueried: fromBlock,
|
|
1202
1221
|
}
|
|
1203
1222
|
}
|
|
1204
1223
|
|
|
1205
|
-
let
|
|
1206
|
-
//
|
|
1207
|
-
//
|
|
1208
|
-
// function when a reorg is detected
|
|
1224
|
+
let onReorg = (~rollbackTargetBlock as _) => {
|
|
1225
|
+
// Drop cached block/transaction/receipt data — after a reorg the cached
|
|
1226
|
+
// entries may refer to orphaned-chain values.
|
|
1209
1227
|
blockLoader := makeBlockLoader()
|
|
1210
1228
|
transactionLoader := makeTransactionLoader()
|
|
1211
1229
|
receiptLoader := makeReceiptLoader()
|
|
1230
|
+
}
|
|
1212
1231
|
|
|
1232
|
+
let getBlockHashes = (~blockNumbers, ~logger as _currentlyUnusedLogger) => {
|
|
1213
1233
|
blockNumbers
|
|
1214
1234
|
->Array.map(blockNum => blockLoader.contents->LazyLoader.get(blockNum))
|
|
1215
1235
|
->Promise.all
|
|
@@ -1243,6 +1263,7 @@ let make = (
|
|
|
1243
1263
|
poweredByHyperSync: false,
|
|
1244
1264
|
pollingInterval: syncConfig.pollingInterval,
|
|
1245
1265
|
getBlockHashes,
|
|
1266
|
+
onReorg,
|
|
1246
1267
|
getHeightOrThrow: async () => {
|
|
1247
1268
|
let timerRef = Hrtime.makeTimer()
|
|
1248
1269
|
let height = try {
|
|
@@ -43,7 +43,8 @@ function parseBlockInfo(json) {
|
|
|
43
43
|
return {
|
|
44
44
|
number: S$RescriptSchema.parseOrThrow(json["number"], Rpc.hexIntSchema),
|
|
45
45
|
timestamp: S$RescriptSchema.parseOrThrow(json["timestamp"], Rpc.hexIntSchema),
|
|
46
|
-
hash: S$RescriptSchema.parseOrThrow(json["hash"], S$RescriptSchema.string)
|
|
46
|
+
hash: S$RescriptSchema.parseOrThrow(json["hash"], S$RescriptSchema.string),
|
|
47
|
+
parentHash: S$RescriptSchema.parseOrThrow(json["parentHash"], S$RescriptSchema.string)
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -917,7 +918,7 @@ function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, low
|
|
|
917
918
|
|
|
918
919
|
function make(param) {
|
|
919
920
|
let lowercaseAddresses = param.lowercaseAddresses;
|
|
920
|
-
let
|
|
921
|
+
let allEventParams = param.allEventParams;
|
|
921
922
|
let eventRouter = param.eventRouter;
|
|
922
923
|
let chain = param.chain;
|
|
923
924
|
let url = param.url;
|
|
@@ -1021,9 +1022,10 @@ function make(param) {
|
|
|
1021
1022
|
let decoder = hscDecoder.contents;
|
|
1022
1023
|
if (decoder !== undefined) {
|
|
1023
1024
|
return decoder;
|
|
1024
|
-
} else {
|
|
1025
|
-
return HyperSyncClient.Decoder.fromSignatures(allEventSignatures);
|
|
1026
1025
|
}
|
|
1026
|
+
let decoder$1 = HyperSyncClient.Decoder.fromParams(allEventParams, !lowercaseAddresses);
|
|
1027
|
+
hscDecoder.contents = decoder$1;
|
|
1028
|
+
return decoder$1;
|
|
1027
1029
|
};
|
|
1028
1030
|
let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, indexingAddresses, knownHeight, partitionId, selection, param, param$1) => {
|
|
1029
1031
|
let startFetchingBatchTimeRef = Hrtime.makeTimer();
|
|
@@ -1038,13 +1040,13 @@ function make(param) {
|
|
|
1038
1040
|
let latestFetchedBlockInfo = match$2.latestFetchedBlockInfo;
|
|
1039
1041
|
let logs = match$2.logs;
|
|
1040
1042
|
let executedBlockInterval = (suggestedToBlock - fromBlock | 0) + 1 | 0;
|
|
1041
|
-
if (executedBlockInterval >= suggestedBlockInterval && !
|
|
1043
|
+
if (executedBlockInterval >= suggestedBlockInterval && !(maxSuggestedBlockIntervalKey in mutSuggestedBlockIntervals)) {
|
|
1042
1044
|
mutSuggestedBlockIntervals[partitionId] = Primitive_int.min(executedBlockInterval + syncConfig.accelerationAdditive | 0, syncConfig.intervalCeiling);
|
|
1043
1045
|
}
|
|
1044
1046
|
let hyperSyncEvents = Belt_Array.map(logs, convertLogToHyperSyncEvent);
|
|
1045
1047
|
let parsedEvents;
|
|
1046
1048
|
try {
|
|
1047
|
-
parsedEvents = await getHscDecoder().
|
|
1049
|
+
parsedEvents = await getHscDecoder().decodeLogs(hyperSyncEvents);
|
|
1048
1050
|
} catch (raw_exn) {
|
|
1049
1051
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
1050
1052
|
throw {
|
|
@@ -1100,7 +1102,7 @@ function make(param) {
|
|
|
1100
1102
|
event: {
|
|
1101
1103
|
contractName: eventConfig.contractName,
|
|
1102
1104
|
eventName: eventConfig.name,
|
|
1103
|
-
params:
|
|
1105
|
+
params: maybeDecodedEvent,
|
|
1104
1106
|
chainId: chain,
|
|
1105
1107
|
srcAddress: routedAddress,
|
|
1106
1108
|
logIndex: log.logIndex,
|
|
@@ -1113,21 +1115,33 @@ function make(param) {
|
|
|
1113
1115
|
}));
|
|
1114
1116
|
let optFirstBlockParent = await firstBlockParentPromise;
|
|
1115
1117
|
let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));
|
|
1116
|
-
let
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1118
|
+
let blockHashes = [];
|
|
1119
|
+
let pushBlockInfo = b => {
|
|
1120
|
+
blockHashes.push({
|
|
1121
|
+
blockHash: b.hash,
|
|
1122
|
+
blockNumber: b.number
|
|
1123
|
+
});
|
|
1124
|
+
if (b.number > 0) {
|
|
1125
|
+
blockHashes.push({
|
|
1126
|
+
blockHash: b.parentHash,
|
|
1127
|
+
blockNumber: b.number - 1 | 0
|
|
1128
|
+
});
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1127
1131
|
};
|
|
1132
|
+
pushBlockInfo(latestFetchedBlockInfo);
|
|
1133
|
+
if (optFirstBlockParent !== undefined) {
|
|
1134
|
+
pushBlockInfo(optFirstBlockParent);
|
|
1135
|
+
}
|
|
1136
|
+
Belt_Array.forEach(logs, log => {
|
|
1137
|
+
blockHashes.push({
|
|
1138
|
+
blockHash: log.blockHash,
|
|
1139
|
+
blockNumber: log.blockNumber
|
|
1140
|
+
});
|
|
1141
|
+
});
|
|
1128
1142
|
return {
|
|
1129
1143
|
knownHeight: knownHeight,
|
|
1130
|
-
|
|
1144
|
+
blockHashes: blockHashes,
|
|
1131
1145
|
parsedQueueItems: parsedQueueItems,
|
|
1132
1146
|
fromBlockQueried: fromBlock,
|
|
1133
1147
|
latestFetchedBlockNumber: latestFetchedBlockInfo.number,
|
|
@@ -1137,25 +1151,25 @@ function make(param) {
|
|
|
1137
1151
|
}
|
|
1138
1152
|
};
|
|
1139
1153
|
};
|
|
1140
|
-
let
|
|
1154
|
+
let onReorg = param => {
|
|
1141
1155
|
blockLoader.contents = makeBlockLoader();
|
|
1142
1156
|
transactionLoader.contents = makeTransactionLoader();
|
|
1143
1157
|
receiptLoader.contents = makeReceiptLoader();
|
|
1144
|
-
return Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => ({
|
|
1145
|
-
TAG: "Ok",
|
|
1146
|
-
_0: rawBlocks.map(json => {
|
|
1147
|
-
let b = parseBlockInfo(json);
|
|
1148
|
-
return {
|
|
1149
|
-
blockHash: b.hash,
|
|
1150
|
-
blockNumber: b.number,
|
|
1151
|
-
blockTimestamp: b.timestamp
|
|
1152
|
-
};
|
|
1153
|
-
})
|
|
1154
|
-
})), exn => Promise.resolve({
|
|
1155
|
-
TAG: "Error",
|
|
1156
|
-
_0: exn
|
|
1157
|
-
}));
|
|
1158
1158
|
};
|
|
1159
|
+
let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => ({
|
|
1160
|
+
TAG: "Ok",
|
|
1161
|
+
_0: rawBlocks.map(json => {
|
|
1162
|
+
let b = parseBlockInfo(json);
|
|
1163
|
+
return {
|
|
1164
|
+
blockHash: b.hash,
|
|
1165
|
+
blockNumber: b.number,
|
|
1166
|
+
blockTimestamp: b.timestamp
|
|
1167
|
+
};
|
|
1168
|
+
})
|
|
1169
|
+
})), exn => Promise.resolve({
|
|
1170
|
+
TAG: "Error",
|
|
1171
|
+
_0: exn
|
|
1172
|
+
}));
|
|
1159
1173
|
let createHeightSubscription = Belt_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chain, onHeight)));
|
|
1160
1174
|
return {
|
|
1161
1175
|
name: name,
|
|
@@ -1181,7 +1195,8 @@ function make(param) {
|
|
|
1181
1195
|
return height;
|
|
1182
1196
|
},
|
|
1183
1197
|
getItemsOrThrow: getItemsOrThrow,
|
|
1184
|
-
createHeightSubscription: createHeightSubscription
|
|
1198
|
+
createHeightSubscription: createHeightSubscription,
|
|
1199
|
+
onReorg: onReorg
|
|
1185
1200
|
};
|
|
1186
1201
|
}
|
|
1187
1202
|
|
|
@@ -39,13 +39,7 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
|
|
|
39
39
|
let reportedHeight = max(endBlock, 1)
|
|
40
40
|
Promise.resolve({
|
|
41
41
|
Source.knownHeight: reportedHeight,
|
|
42
|
-
|
|
43
|
-
rangeLastBlock: {
|
|
44
|
-
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
45
|
-
blockNumber: reportedHeight,
|
|
46
|
-
},
|
|
47
|
-
prevRangeLastBlock: None,
|
|
48
|
-
},
|
|
42
|
+
blockHashes: [],
|
|
49
43
|
parsedQueueItems: result,
|
|
50
44
|
fromBlockQueried: 0,
|
|
51
45
|
latestFetchedBlockNumber: reportedHeight,
|
|
@@ -22,13 +22,7 @@ function make(items, endBlock, chain) {
|
|
|
22
22
|
let reportedHeight = Primitive_int.max(endBlock, 1);
|
|
23
23
|
return Promise.resolve({
|
|
24
24
|
knownHeight: reportedHeight,
|
|
25
|
-
|
|
26
|
-
rangeLastBlock: {
|
|
27
|
-
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
28
|
-
blockNumber: reportedHeight
|
|
29
|
-
},
|
|
30
|
-
prevRangeLastBlock: undefined
|
|
31
|
-
},
|
|
25
|
+
blockHashes: [],
|
|
32
26
|
parsedQueueItems: result,
|
|
33
27
|
fromBlockQueried: 0,
|
|
34
28
|
latestFetchedBlockNumber: reportedHeight,
|
package/src/sources/Source.res
CHANGED
|
@@ -12,7 +12,11 @@ Thes response returned from a block range fetch
|
|
|
12
12
|
*/
|
|
13
13
|
type blockRangeFetchResponse = {
|
|
14
14
|
knownHeight: int,
|
|
15
|
-
|
|
15
|
+
// Best-effort (blockNumber, blockHash) pairs observed while fetching this range.
|
|
16
|
+
// Used by reorg detection; gaps are OK, no extra requests are made to fill them.
|
|
17
|
+
// Duplicates with the same block number are allowed — registerReorgGuard treats
|
|
18
|
+
// a within-array hash mismatch on the same block number as a reorg.
|
|
19
|
+
blockHashes: array<ReorgDetection.blockData>,
|
|
16
20
|
parsedQueueItems: array<Internal.item>,
|
|
17
21
|
fromBlockQueried: int,
|
|
18
22
|
latestFetchedBlockNumber: int,
|
|
@@ -58,4 +62,7 @@ type t = {
|
|
|
58
62
|
~logger: Pino.t,
|
|
59
63
|
) => promise<blockRangeFetchResponse>,
|
|
60
64
|
createHeightSubscription?: (~onHeight: int => unit) => unit => unit,
|
|
65
|
+
// Invoked by SourceManager once a rollback target is known so the source can
|
|
66
|
+
// drop any state that may now point at an orphaned chain (e.g. RPC block cache).
|
|
67
|
+
onReorg?: (~rollbackTargetBlock: int) => unit,
|
|
61
68
|
}
|
|
@@ -36,6 +36,15 @@ type t = {
|
|
|
36
36
|
|
|
37
37
|
let getActiveSource = sourceManager => sourceManager.activeSource
|
|
38
38
|
|
|
39
|
+
let onReorg = (sourceManager: t, ~rollbackTargetBlock) => {
|
|
40
|
+
sourceManager.sourcesState->Array.forEach(({source}) => {
|
|
41
|
+
switch source.onReorg {
|
|
42
|
+
| Some(cb) => cb(~rollbackTargetBlock)
|
|
43
|
+
| None => ()
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
type sourceRole = Primary | Secondary
|
|
40
49
|
|
|
41
50
|
// Determines whether a source is Primary or Secondary given the current mode.
|
|
@@ -17,6 +17,15 @@ function getActiveSource(sourceManager) {
|
|
|
17
17
|
return sourceManager.activeSource;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function onReorg(sourceManager, rollbackTargetBlock) {
|
|
21
|
+
sourceManager.sourcesState.forEach(param => {
|
|
22
|
+
let cb = param.source.onReorg;
|
|
23
|
+
if (cb !== undefined) {
|
|
24
|
+
return cb(rollbackTargetBlock);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
function getSourceRole(sourceFor, isRealtime, hasRealtime) {
|
|
21
30
|
if (isRealtime) {
|
|
22
31
|
switch (sourceFor) {
|
|
@@ -547,6 +556,7 @@ export {
|
|
|
547
556
|
getSourceRole,
|
|
548
557
|
make,
|
|
549
558
|
getActiveSource,
|
|
559
|
+
onReorg,
|
|
550
560
|
fetchNext,
|
|
551
561
|
waitForNewBlock,
|
|
552
562
|
executeQuery,
|
package/svm.schema.json
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
"description": "Schema for a YAML config for an envio Svm indexer",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
|
+
"name": {
|
|
8
|
+
"description": "Name of the project",
|
|
9
|
+
"type": "string"
|
|
10
|
+
},
|
|
7
11
|
"description": {
|
|
8
12
|
"description": "Description of the project",
|
|
9
13
|
"type": [
|
|
@@ -11,10 +15,6 @@
|
|
|
11
15
|
"null"
|
|
12
16
|
]
|
|
13
17
|
},
|
|
14
|
-
"name": {
|
|
15
|
-
"description": "Name of the project",
|
|
16
|
-
"type": "string"
|
|
17
|
-
},
|
|
18
18
|
"schema": {
|
|
19
19
|
"description": "Custom path to schema.graphql file",
|
|
20
20
|
"type": [
|
|
@@ -133,6 +133,13 @@
|
|
|
133
133
|
"Chain": {
|
|
134
134
|
"type": "object",
|
|
135
135
|
"properties": {
|
|
136
|
+
"skip": {
|
|
137
|
+
"description": "Excludes the chain from indexing and migrations. Code generation is unaffected. For testing, prefer using a test framework instead.",
|
|
138
|
+
"type": [
|
|
139
|
+
"boolean",
|
|
140
|
+
"null"
|
|
141
|
+
]
|
|
142
|
+
},
|
|
136
143
|
"rpc": {
|
|
137
144
|
"description": "RPC endpoint URL for connecting to the Svm cluster to fetch blockchain data.",
|
|
138
145
|
"type": "string"
|