envio 3.13.0-alpha.0 → 3.13.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/package.json +6 -8
- package/src/BatchProcessing.res +4 -5
- package/src/BatchProcessing.res.mjs +4 -11
- package/src/ChainFetching.res +18 -38
- package/src/ChainFetching.res.mjs +14 -20
- package/src/ChainState.res +113 -77
- package/src/ChainState.res.mjs +90 -73
- package/src/ChainState.resi +14 -5
- package/src/Config.res +14 -17
- package/src/Config.res.mjs +5 -20
- package/src/CrossChainState.res +68 -20
- package/src/CrossChainState.res.mjs +48 -5
- package/src/CrossChainState.resi +1 -0
- package/src/Env.res +2 -2
- package/src/ErrorHandling.res +15 -4
- package/src/ErrorHandling.res.mjs +16 -5
- package/src/FinalizeBackfill.res +21 -9
- package/src/FinalizeBackfill.res.mjs +17 -4
- package/src/HandlerRegister.res +0 -37
- package/src/HandlerRegister.res.mjs +0 -18
- package/src/IndexerState.res +2 -0
- package/src/IndexerState.res.mjs +5 -0
- package/src/IndexerState.resi +1 -0
- package/src/Logging.res +6 -38
- package/src/Logging.res.mjs +5 -32
- package/src/Main.res +6 -9
- package/src/Main.res.mjs +3 -5
- package/src/Metrics.res +9 -4
- package/src/Metrics.res.mjs +3 -3
- package/src/Persistence.res +6 -3
- package/src/Persistence.res.mjs +5 -3
- package/src/PgStorage.res +2 -2
- package/src/PgStorage.res.mjs +2 -2
- package/src/Rollback.res +3 -3
- package/src/Server.res +0 -3
- package/src/SimulateItems.res +1 -1
- package/src/SimulateItems.res.mjs +1 -1
- package/src/Supervisor.res +236 -109
- package/src/Supervisor.res.mjs +185 -55
- package/src/TestIndexer.res +6 -3
- package/src/TestIndexer.res.mjs +3 -3
- package/src/Worker.res +6 -0
- package/src/Worker.res.mjs +2 -1
- package/src/bindings/NodeJs.res +25 -16
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/sources/AddressSet.res +5 -3
- package/src/sources/AddressStore.res +19 -11
- package/src/sources/AddressStore.res.mjs +2 -7
- package/src/sources/BlockStore.res +10 -9
- package/src/sources/BlockStore.res.mjs +4 -4
- package/src/sources/ChainSources.res +4 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +4 -0
- package/src/sources/EvmChain.res.mjs +3 -1
- package/src/sources/EvmEventItem.res +56 -0
- package/src/sources/EvmEventItem.res.mjs +32 -0
- package/src/sources/EvmHyperSyncSource.res +7 -37
- package/src/sources/EvmHyperSyncSource.res.mjs +8 -29
- package/src/sources/EvmRpcClient.res +41 -59
- package/src/sources/EvmRpcClient.res.mjs +4 -54
- package/src/sources/EvmRpcWs.res +4 -1
- package/src/sources/EvmRpcWs.res.mjs +6 -2
- package/src/sources/FuelHyperSyncSource.res +6 -4
- package/src/sources/FuelHyperSyncSource.res.mjs +7 -9
- package/src/sources/HeightFeed.res +7 -1
- package/src/sources/HeightFeed.res.mjs +9 -7
- package/src/sources/HyperSyncClient.res +1 -14
- package/src/sources/RequestStat.res +7 -0
- package/src/sources/RequestStat.res.mjs +14 -1
- package/src/sources/RpcSource.res +100 -1043
- package/src/sources/RpcSource.res.mjs +81 -1056
- package/src/sources/SimulateSource.res +2 -5
- package/src/sources/SimulateSource.res.mjs +2 -3
- package/src/sources/Source.res +34 -12
- package/src/sources/Source.res.mjs +11 -0
- package/src/sources/SourceManager.res +111 -31
- package/src/sources/SourceManager.res.mjs +65 -31
- package/src/sources/SourceManager.resi +4 -0
- package/src/sources/StartBlockResolver.res +8 -5
- package/src/sources/StartBlockResolver.res.mjs +4 -2
- package/src/sources/SvmHyperSyncSource.res +4 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -6
- package/src/sources/TransactionStore.res +9 -6
- package/src/sources/TransactionStore.res.mjs +2 -2
- package/src/tui/Tui.res +4 -18
- package/src/tui/Tui.res.mjs +3 -6
- package/src/LazyLoader.res +0 -135
- package/src/LazyLoader.res.mjs +0 -118
- package/src/bindings/SDSL.res +0 -12
- package/src/bindings/SDSL.res.mjs +0 -9
- package/src/bindings/Yargs.res +0 -8
- package/src/bindings/Yargs.res.mjs +0 -2
- package/src/sources/Rpc.res +0 -185
- package/src/sources/Rpc.res.mjs +0 -183
package/src/ChainState.res.mjs
CHANGED
|
@@ -21,7 +21,6 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
21
21
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
22
22
|
import * as ContractMapping from "./ContractMapping.res.mjs";
|
|
23
23
|
import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
|
|
24
|
-
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
25
24
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
26
25
|
import * as TransactionStore from "./sources/TransactionStore.res.mjs";
|
|
27
26
|
import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
|
|
@@ -56,7 +55,7 @@ function validateOnEventRegistrations(chainId, registrations) {
|
|
|
56
55
|
});
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, sourceManager, committedProgressBlockNumber, committedProgressBlockTimeOpt, safeCheckpointTrackingOpt, shouldRollbackOnReorg, maxReorgDepth, isInReorgThresholdOpt, numEventsProcessedOpt, timestampCaughtUpToHeadOrEndblockOpt, isProgressAtHeadOpt, transactionStoreOpt, chainDensityOpt, blockStoreOpt, reorgThresholdReadyToleranceOpt, perChainEntitiesOpt, logger) {
|
|
58
|
+
function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, sourceManager, committedProgressBlockNumber, committedProgressBlockTimeOpt, safeCheckpointTrackingOpt, shouldRollbackOnReorg, maxReorgDepth, isInReorgThresholdOpt, numEventsProcessedOpt, timestampCaughtUpToHeadOrEndblockOpt, isProgressAtHeadOpt, transactionStoreOpt, chainDensityOpt, blockStoreOpt, shouldChecksumOpt, reorgThresholdReadyToleranceOpt, perChainEntitiesOpt, logger) {
|
|
60
59
|
let onEventRegistrations = onEventRegistrationsOpt !== undefined ? onEventRegistrationsOpt : [];
|
|
61
60
|
let committedProgressBlockTime = committedProgressBlockTimeOpt !== undefined ? Primitive_option.valFromOption(committedProgressBlockTimeOpt) : undefined;
|
|
62
61
|
let safeCheckpointTracking = safeCheckpointTrackingOpt !== undefined ? Primitive_option.valFromOption(safeCheckpointTrackingOpt) : undefined;
|
|
@@ -64,9 +63,10 @@ function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, so
|
|
|
64
63
|
let numEventsProcessed = numEventsProcessedOpt !== undefined ? numEventsProcessedOpt : 0;
|
|
65
64
|
let timestampCaughtUpToHeadOrEndblock = timestampCaughtUpToHeadOrEndblockOpt !== undefined ? Primitive_option.valFromOption(timestampCaughtUpToHeadOrEndblockOpt) : undefined;
|
|
66
65
|
let isProgressAtHead = isProgressAtHeadOpt !== undefined ? isProgressAtHeadOpt : false;
|
|
67
|
-
let transactionStore = transactionStoreOpt !== undefined ? Primitive_option.valFromOption(transactionStoreOpt) : TransactionStore.make("evm"
|
|
66
|
+
let transactionStore = transactionStoreOpt !== undefined ? Primitive_option.valFromOption(transactionStoreOpt) : TransactionStore.make("evm");
|
|
68
67
|
let chainDensity = chainDensityOpt !== undefined ? Primitive_option.valFromOption(chainDensityOpt) : undefined;
|
|
69
|
-
let blockStore = blockStoreOpt !== undefined ? Primitive_option.valFromOption(blockStoreOpt) : BlockStore.make("evm"
|
|
68
|
+
let blockStore = blockStoreOpt !== undefined ? Primitive_option.valFromOption(blockStoreOpt) : BlockStore.make("evm");
|
|
69
|
+
let shouldChecksum = shouldChecksumOpt !== undefined ? shouldChecksumOpt : false;
|
|
70
70
|
let reorgThresholdReadyTolerance = reorgThresholdReadyToleranceOpt !== undefined ? reorgThresholdReadyToleranceOpt : 100;
|
|
71
71
|
let perChainEntities = perChainEntitiesOpt !== undefined ? perChainEntitiesOpt : [];
|
|
72
72
|
validateOnEventRegistrations(chainConfig.id, onEventRegistrations);
|
|
@@ -89,6 +89,7 @@ function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, so
|
|
|
89
89
|
shouldRollbackOnReorg: shouldRollbackOnReorg,
|
|
90
90
|
maxReorgDepth: maxReorgDepth,
|
|
91
91
|
isInReorgThreshold: isInReorgThreshold,
|
|
92
|
+
shouldChecksum: shouldChecksum,
|
|
92
93
|
transactionStore: transactionStore,
|
|
93
94
|
blockStore: blockStore,
|
|
94
95
|
reorgThresholdReadyTolerance: reorgThresholdReadyTolerance,
|
|
@@ -97,7 +98,7 @@ function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, so
|
|
|
97
98
|
blockRangeFetchCount: 0,
|
|
98
99
|
blockRangeFetchedEvents: 0,
|
|
99
100
|
blockRangeFetchedBlocks: 0,
|
|
100
|
-
|
|
101
|
+
reportedFinished: false,
|
|
101
102
|
reorgCount: 0,
|
|
102
103
|
reorgDetectedBlock: undefined,
|
|
103
104
|
rollbackTargetBlock: undefined,
|
|
@@ -138,7 +139,7 @@ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInR
|
|
|
138
139
|
}
|
|
139
140
|
});
|
|
140
141
|
let lowercaseAddresses = config.lowercaseAddresses;
|
|
141
|
-
let addressStore = AddressStore.make(config.ecosystem.name,
|
|
142
|
+
let addressStore = AddressStore.make(config.ecosystem.name, AddressStore.contractsOf(onEventRegistrations, contractMapping));
|
|
142
143
|
let match$1 = config.ecosystem.name;
|
|
143
144
|
let tmp;
|
|
144
145
|
switch (match$1) {
|
|
@@ -156,18 +157,19 @@ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInR
|
|
|
156
157
|
return reorgCheckpoint;
|
|
157
158
|
}
|
|
158
159
|
});
|
|
159
|
-
let
|
|
160
|
-
let
|
|
160
|
+
let blockStore = BlockStore.make(config.ecosystem.name);
|
|
161
|
+
let transactionStore = TransactionStore.make(config.ecosystem.name);
|
|
162
|
+
let sources = ChainSources.make(chainConfig, onEventRegistrations, addressStore, lowercaseAddresses, blockStore, transactionStore);
|
|
161
163
|
if (Utils.$$Array.notEmpty(chainReorgCheckpoints)) {
|
|
162
164
|
let seedPage = BlockStore.fromJs(chainReorgCheckpoints.map(cp => ({
|
|
163
165
|
blockNumber: cp.block_number,
|
|
164
166
|
blockHash: cp.block_hash
|
|
165
|
-
})), config.ecosystem.name
|
|
167
|
+
})), config.ecosystem.name);
|
|
166
168
|
blockStore.merge(seedPage, 0, false);
|
|
167
169
|
}
|
|
168
170
|
let firstEventBlock$1 = fetchState.firstEventBlock;
|
|
169
171
|
let chainDensity = firstEventBlock$1 !== undefined && progressBlockNumber > firstEventBlock$1 && numEventsProcessed > 0 ? numEventsProcessed / (progressBlockNumber - firstEventBlock$1 | 0) : undefined;
|
|
170
|
-
return make(chainConfig, fetchState, onEventRegistrations, addressStore, SourceManager.make(sources, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), progressBlockNumber, Primitive_option.some(committedProgressBlockTime), Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), config.shouldRollbackOnReorg, maxReorgDepth, isInReorgThreshold, numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, Primitive_option.some(
|
|
172
|
+
return make(chainConfig, fetchState, onEventRegistrations, addressStore, SourceManager.make(sources, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), progressBlockNumber, Primitive_option.some(committedProgressBlockTime), Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), config.shouldRollbackOnReorg, maxReorgDepth, isInReorgThreshold, numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, Primitive_option.some(transactionStore), Primitive_option.some(chainDensity), Primitive_option.some(blockStore), !lowercaseAddresses, config.reorgThresholdReadyTolerance, EntityTables.perChain(config.userEntities), logger);
|
|
171
173
|
}
|
|
172
174
|
|
|
173
175
|
function logger(cs) {
|
|
@@ -178,6 +180,14 @@ function blockStore(cs) {
|
|
|
178
180
|
return cs.blockStore;
|
|
179
181
|
}
|
|
180
182
|
|
|
183
|
+
function transactionStore(cs) {
|
|
184
|
+
return cs.transactionStore;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function shouldChecksum(cs) {
|
|
188
|
+
return cs.shouldChecksum;
|
|
189
|
+
}
|
|
190
|
+
|
|
181
191
|
function entities(cs) {
|
|
182
192
|
return cs.entities;
|
|
183
193
|
}
|
|
@@ -210,10 +220,6 @@ function safeCheckpointTracking(cs) {
|
|
|
210
220
|
return cs.safeCheckpointTracking;
|
|
211
221
|
}
|
|
212
222
|
|
|
213
|
-
function isProgressAtHead(cs) {
|
|
214
|
-
return cs.isProgressAtHead;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
223
|
function committedProgressBlockNumber(cs) {
|
|
218
224
|
return cs.committedProgressBlockNumber;
|
|
219
225
|
}
|
|
@@ -256,7 +262,7 @@ function knownHeight(cs) {
|
|
|
256
262
|
}
|
|
257
263
|
|
|
258
264
|
function contractAddresses(cs, contractName) {
|
|
259
|
-
return cs.addressStore.contractAddresses(contractName);
|
|
265
|
+
return cs.addressStore.contractAddresses(contractName, cs.shouldChecksum);
|
|
260
266
|
}
|
|
261
267
|
|
|
262
268
|
function drainAddressesForWrite(cs, toBlockInclusive, checkpointBlockNumbers) {
|
|
@@ -400,41 +406,6 @@ function dispatch(cs, executeQuery, waitForNewBlock, onNewBlock, action, stateId
|
|
|
400
406
|
return SourceManager.dispatch(cs.sourceManager, cs.fetchState, executeQuery, waitForNewBlock, onNewBlock, action, stateId);
|
|
401
407
|
}
|
|
402
408
|
|
|
403
|
-
function fetchedTo(cs) {
|
|
404
|
-
let endBlock = cs.fetchState.endBlock;
|
|
405
|
-
if (endBlock !== undefined && endBlock <= (cs.fetchState.knownHeight - cs.fetchState.blockLag | 0)) {
|
|
406
|
-
return [
|
|
407
|
-
"the end block",
|
|
408
|
-
endBlock
|
|
409
|
-
];
|
|
410
|
-
}
|
|
411
|
-
if (cs.isInReorgThreshold) {
|
|
412
|
-
return [
|
|
413
|
-
"the chain head",
|
|
414
|
-
cs.fetchState.knownHeight
|
|
415
|
-
];
|
|
416
|
-
} else {
|
|
417
|
-
return [
|
|
418
|
-
"the safe block",
|
|
419
|
-
cs.fetchState.knownHeight - cs.fetchState.blockLag | 0
|
|
420
|
-
];
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
function takeFetchedTo(cs) {
|
|
425
|
-
let match = fetchedTo(cs);
|
|
426
|
-
let target = match[0];
|
|
427
|
-
if (Primitive_object.equal(cs.reportedFetchedTo, target)) {
|
|
428
|
-
return;
|
|
429
|
-
} else {
|
|
430
|
-
cs.reportedFetchedTo = target;
|
|
431
|
-
return [
|
|
432
|
-
target,
|
|
433
|
-
match[1]
|
|
434
|
-
];
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
409
|
function hasProcessedToEndblock(cs) {
|
|
439
410
|
let fetchState = cs.fetchState;
|
|
440
411
|
let committedProgressBlockNumber = cs.committedProgressBlockNumber;
|
|
@@ -446,15 +417,46 @@ function hasProcessedToEndblock(cs) {
|
|
|
446
417
|
}
|
|
447
418
|
}
|
|
448
419
|
|
|
449
|
-
function
|
|
450
|
-
|
|
451
|
-
let committedProgressBlockNumber = cs.committedProgressBlockNumber;
|
|
452
|
-
let atEndBlock = Stdlib_Option.mapOr(fetchState.endBlock, false, endBlock => committedProgressBlockNumber >= endBlock);
|
|
453
|
-
let atHead = fetchState.knownHeight > 0 && committedProgressBlockNumber >= Primitive_int.max(0, fetchState.knownHeight - cs.chainConfig.blockLag | 0);
|
|
454
|
-
if (atEndBlock) {
|
|
420
|
+
function hasCaughtUp(cs) {
|
|
421
|
+
if (cs.isProgressAtHead) {
|
|
455
422
|
return true;
|
|
456
423
|
} else {
|
|
457
|
-
|
|
424
|
+
let fetchState = cs.fetchState;
|
|
425
|
+
let committedProgressBlockNumber = cs.committedProgressBlockNumber;
|
|
426
|
+
let atEndBlock = Stdlib_Option.mapOr(fetchState.endBlock, false, endBlock => committedProgressBlockNumber >= endBlock);
|
|
427
|
+
let atHead = fetchState.knownHeight > 0 && committedProgressBlockNumber >= Primitive_int.max(0, fetchState.knownHeight - cs.chainConfig.blockLag | 0);
|
|
428
|
+
if (atEndBlock) {
|
|
429
|
+
return true;
|
|
430
|
+
} else {
|
|
431
|
+
return atHead;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function takeFinished(cs) {
|
|
437
|
+
if (cs.reportedFinished) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
let match = cs.fetchState.endBlock;
|
|
441
|
+
let match$1 = hasProcessedToEndblock(cs);
|
|
442
|
+
let match$2 = hasCaughtUp(cs);
|
|
443
|
+
if (match !== undefined && match$1) {
|
|
444
|
+
cs.reportedFinished = true;
|
|
445
|
+
return {
|
|
446
|
+
TAG: "EndBlock",
|
|
447
|
+
_0: match
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
if (match$2) {
|
|
451
|
+
cs.reportedFinished = true;
|
|
452
|
+
if (cs.timestampCaughtUpToHeadOrEndblock !== undefined) {
|
|
453
|
+
return;
|
|
454
|
+
} else {
|
|
455
|
+
return {
|
|
456
|
+
TAG: "Backfill",
|
|
457
|
+
_0: cs.committedProgressBlockNumber
|
|
458
|
+
};
|
|
459
|
+
}
|
|
458
460
|
}
|
|
459
461
|
}
|
|
460
462
|
|
|
@@ -548,12 +550,12 @@ function groupBatchItems(items) {
|
|
|
548
550
|
];
|
|
549
551
|
}
|
|
550
552
|
|
|
551
|
-
async function applyTransactionGroups(store, g) {
|
|
553
|
+
async function applyTransactionGroups(store, g, shouldChecksum) {
|
|
552
554
|
if (!Utils.$$Array.notEmpty(g.payloadGroups)) {
|
|
553
555
|
return;
|
|
554
556
|
}
|
|
555
557
|
if (g.anyTransactionFieldSelected) {
|
|
556
|
-
let txs = await store.materialize(g.txBlockNumbers, g.transactionIndices, g.transactionMasks);
|
|
558
|
+
let txs = await store.materialize(g.txBlockNumbers, g.transactionIndices, g.transactionMasks, shouldChecksum);
|
|
557
559
|
g.payloadGroups.forEach((payloads, i) => {
|
|
558
560
|
let tx = txs[i];
|
|
559
561
|
payloads.forEach(payload => {
|
|
@@ -574,11 +576,11 @@ async function applyTransactionGroups(store, g) {
|
|
|
574
576
|
});
|
|
575
577
|
}
|
|
576
578
|
|
|
577
|
-
async function applyBlockGroups(store, g) {
|
|
579
|
+
async function applyBlockGroups(store, g, shouldChecksum) {
|
|
578
580
|
if (!Utils.$$Array.notEmpty(g.blockItemGroups)) {
|
|
579
581
|
return;
|
|
580
582
|
}
|
|
581
|
-
let blocks = await store.materialize(g.blockBlockNumbers, g.blockMasks);
|
|
583
|
+
let blocks = await store.materialize(g.blockBlockNumbers, g.blockMasks, shouldChecksum);
|
|
582
584
|
g.blockItemGroups.forEach((group, i) => {
|
|
583
585
|
let block = blocks[i];
|
|
584
586
|
group.forEach(ei => {
|
|
@@ -590,23 +592,20 @@ async function applyBlockGroups(store, g) {
|
|
|
590
592
|
async function materializeBatchItems(cs, items) {
|
|
591
593
|
let match = groupBatchItems(items);
|
|
592
594
|
await Promise.all([
|
|
593
|
-
applyTransactionGroups(cs.transactionStore, match[0]),
|
|
594
|
-
applyBlockGroups(cs.blockStore, match[1])
|
|
595
|
+
applyTransactionGroups(cs.transactionStore, match[0], cs.shouldChecksum),
|
|
596
|
+
applyBlockGroups(cs.blockStore, match[1], cs.shouldChecksum)
|
|
595
597
|
]);
|
|
596
598
|
}
|
|
597
599
|
|
|
598
|
-
async function materializePageItems(items, transactionStore, blockStore) {
|
|
600
|
+
async function materializePageItems(items, transactionStore, blockStore, shouldChecksum) {
|
|
599
601
|
let match = groupBatchItems(items);
|
|
600
602
|
await Promise.all([
|
|
601
|
-
|
|
602
|
-
applyBlockGroups(blockStore, match[1])
|
|
603
|
+
applyTransactionGroups(transactionStore, match[0], shouldChecksum),
|
|
604
|
+
applyBlockGroups(blockStore, match[1], shouldChecksum)
|
|
603
605
|
]);
|
|
604
606
|
}
|
|
605
607
|
|
|
606
|
-
function handleQueryResult(cs, query, newItems, newRegistrations, latestFetchedBlock, knownHeight
|
|
607
|
-
if (txPage !== undefined) {
|
|
608
|
-
cs.transactionStore.merge(Primitive_option.valFromOption(txPage));
|
|
609
|
-
}
|
|
608
|
+
function handleQueryResult(cs, query, newItems, newRegistrations, latestFetchedBlock, knownHeight) {
|
|
610
609
|
let fs = newRegistrations.length !== 0 ? FetchState.registerDynamicContracts(cs.fetchState, cs.addressStore, Primitive_int.max(knownHeight, latestFetchedBlock), newRegistrations) : cs.fetchState;
|
|
611
610
|
cs.fetchState = FetchState.updateKnownHeight(FetchState.handleQueryResult(fs, query, latestFetchedBlock, newItems), knownHeight);
|
|
612
611
|
cs.pendingBudget = Primitive_float.max(0, cs.pendingBudget - query.itemsEst);
|
|
@@ -703,6 +702,19 @@ function shouldSaveHistory(cs) {
|
|
|
703
702
|
}
|
|
704
703
|
}
|
|
705
704
|
|
|
705
|
+
function reorgThresholdLiftsCeiling(cs) {
|
|
706
|
+
let ceiling = blockLag => {
|
|
707
|
+
let head = Primitive_int.max(0, cs.fetchState.knownHeight - blockLag | 0);
|
|
708
|
+
let endBlock = cs.fetchState.endBlock;
|
|
709
|
+
if (endBlock !== undefined) {
|
|
710
|
+
return Primitive_int.min(endBlock, head);
|
|
711
|
+
} else {
|
|
712
|
+
return head;
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
return ceiling(cs.chainConfig.blockLag) > ceiling(cs.fetchState.blockLag);
|
|
716
|
+
}
|
|
717
|
+
|
|
706
718
|
function toChainMetadata(cs) {
|
|
707
719
|
return {
|
|
708
720
|
first_event_block: Stdlib_Null.fromOption(cs.fetchState.firstEventBlock),
|
|
@@ -919,6 +931,8 @@ function rollback(cs, rolledBackTo) {
|
|
|
919
931
|
return rolledBackAddresses$1;
|
|
920
932
|
}
|
|
921
933
|
|
|
934
|
+
let reorgThresholdEntryMessage = "Indexing the latest blocks now. These can be reorged, so the indexer starts storing a history of every change to roll back with.";
|
|
935
|
+
|
|
922
936
|
export {
|
|
923
937
|
configStorageRows,
|
|
924
938
|
seedConfigAddresses,
|
|
@@ -926,6 +940,8 @@ export {
|
|
|
926
940
|
makeFromDbState,
|
|
927
941
|
logger,
|
|
928
942
|
blockStore,
|
|
943
|
+
transactionStore,
|
|
944
|
+
shouldChecksum,
|
|
929
945
|
entities,
|
|
930
946
|
resetEntities,
|
|
931
947
|
sourceManager,
|
|
@@ -934,7 +950,6 @@ export {
|
|
|
934
950
|
getReorgThresholdBlockNumbersBelow,
|
|
935
951
|
getLatestValidScannedBlock,
|
|
936
952
|
safeCheckpointTracking,
|
|
937
|
-
isProgressAtHead,
|
|
938
953
|
committedProgressBlockNumber,
|
|
939
954
|
committedProgressBlockTime,
|
|
940
955
|
numEventsProcessed,
|
|
@@ -964,9 +979,11 @@ export {
|
|
|
964
979
|
toChainBeforeBatch,
|
|
965
980
|
isReadyToEnterReorgThreshold,
|
|
966
981
|
isReadyToEnterReorgThresholdAfterBatch,
|
|
967
|
-
|
|
982
|
+
takeFinished,
|
|
983
|
+
reorgThresholdLiftsCeiling,
|
|
984
|
+
reorgThresholdEntryMessage,
|
|
968
985
|
hasProcessedToEndblock,
|
|
969
|
-
|
|
986
|
+
hasCaughtUp,
|
|
970
987
|
getHighestBlockBelowThreshold,
|
|
971
988
|
isActivelyIndexing,
|
|
972
989
|
isReady,
|
package/src/ChainState.resi
CHANGED
|
@@ -34,6 +34,7 @@ let make: (
|
|
|
34
34
|
~transactionStore: TransactionStore.t=?,
|
|
35
35
|
~chainDensity: option<float>=?,
|
|
36
36
|
~blockStore: BlockStore.t=?,
|
|
37
|
+
~shouldChecksum: bool=?,
|
|
37
38
|
~reorgThresholdReadyTolerance: int=?,
|
|
38
39
|
~perChainEntities: array<Internal.entityConfig>=?,
|
|
39
40
|
~logger: Pino.t,
|
|
@@ -54,6 +55,8 @@ let makeFromDbState: (
|
|
|
54
55
|
// Accessors.
|
|
55
56
|
let logger: t => Pino.t
|
|
56
57
|
let blockStore: t => BlockStore.t
|
|
58
|
+
let transactionStore: t => TransactionStore.t
|
|
59
|
+
let shouldChecksum: t => bool
|
|
57
60
|
let entities: t => EntityTables.t
|
|
58
61
|
let resetEntities: (t, ~perChainEntities: array<Internal.entityConfig>) => unit
|
|
59
62
|
let sourceManager: t => SourceManager.t
|
|
@@ -67,7 +70,6 @@ let getLatestValidScannedBlock: (
|
|
|
67
70
|
~blockNumbers: array<int>,
|
|
68
71
|
) => option<int>
|
|
69
72
|
let safeCheckpointTracking: t => option<SafeCheckpointTracking.t>
|
|
70
|
-
let isProgressAtHead: t => bool
|
|
71
73
|
let committedProgressBlockNumber: t => int
|
|
72
74
|
let committedProgressBlockTime: t => option<int>
|
|
73
75
|
let numEventsProcessed: t => float
|
|
@@ -124,9 +126,12 @@ let isReadyToEnterReorgThreshold: t => bool
|
|
|
124
126
|
let isReadyToEnterReorgThresholdAfterBatch: (t, ~batch: Batch.t) => bool
|
|
125
127
|
|
|
126
128
|
// Derived (pure).
|
|
127
|
-
|
|
129
|
+
type finished = EndBlock(int) | Backfill(int)
|
|
130
|
+
let takeFinished: t => option<finished>
|
|
131
|
+
let reorgThresholdLiftsCeiling: t => bool
|
|
132
|
+
let reorgThresholdEntryMessage: string
|
|
128
133
|
let hasProcessedToEndblock: t => bool
|
|
129
|
-
let
|
|
134
|
+
let hasCaughtUp: t => bool
|
|
130
135
|
let getHighestBlockBelowThreshold: t => int
|
|
131
136
|
let isActivelyIndexing: t => bool
|
|
132
137
|
let isReady: t => bool
|
|
@@ -141,14 +146,18 @@ let handleQueryResult: (
|
|
|
141
146
|
~newRegistrations: array<AddressStore.registration>,
|
|
142
147
|
~latestFetchedBlock: int,
|
|
143
148
|
~knownHeight: int,
|
|
144
|
-
~transactionStore: option<TransactionStore.t>,
|
|
145
149
|
) => unit
|
|
146
150
|
let materializeBatchItems: (t, ~items: array<Internal.item>) => promise<unit>
|
|
147
151
|
let materializePageItems: (
|
|
148
152
|
~items: array<Internal.item>,
|
|
149
|
-
~transactionStore:
|
|
153
|
+
~transactionStore: TransactionStore.t,
|
|
150
154
|
~blockStore: BlockStore.t,
|
|
155
|
+
~shouldChecksum: bool,
|
|
151
156
|
) => promise<unit>
|
|
157
|
+
// Merges the page's blocks into the chain's store as it checks them: the check
|
|
158
|
+
// is the merge's own conflict report, so a page that passes is already applied.
|
|
159
|
+
// Its transactions are a separate page, merged by the caller once this returns
|
|
160
|
+
// no reorg.
|
|
152
161
|
let registerReorgGuard: (
|
|
153
162
|
t,
|
|
154
163
|
~blockStore: BlockStore.t,
|
package/src/Config.res
CHANGED
|
@@ -625,20 +625,14 @@ let getChain = (config, ~chainId) =>
|
|
|
625
625
|
"No chain with id " ++ chainId->ChainId.toString ++ " found in config.yaml",
|
|
626
626
|
)
|
|
627
627
|
|
|
628
|
-
// Whether every entity belongs to exactly one chain.
|
|
629
|
-
//
|
|
630
|
-
//
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
// and its chain-scoped lines already carry theirs.
|
|
637
|
-
let logContext = (config: t): option<dict<JSON.t>> =>
|
|
638
|
-
switch (config.isolated, config.chainMap->ChainMap.keys) {
|
|
639
|
-
| (true, [chainId]) =>
|
|
640
|
-
Some(Dict.fromArray([("chainId", chainId->S.reverseConvertToJsonOrThrow(ChainId.schema))]))
|
|
641
|
-
| _ => None
|
|
628
|
+
// Whether every entity belongs to exactly one chain. Read off the checkpoint
|
|
629
|
+
// sequence rather than the entities again: a chain gets a counter of its own
|
|
630
|
+
// only when no other chain can reach its rows, which is the same fact and the
|
|
631
|
+
// one that makes splitting a run across processes safe.
|
|
632
|
+
let isPerChain = (config: t) =>
|
|
633
|
+
switch config.checkpointSequence {
|
|
634
|
+
| PerChain => true
|
|
635
|
+
| SharedAcrossChains => false
|
|
642
636
|
}
|
|
643
637
|
|
|
644
638
|
// Narrows a config to the chains one `envio start --chain` process drives.
|
|
@@ -1237,9 +1231,11 @@ let prime = (json: JSON.t): unit => {
|
|
|
1237
1231
|
cached := None
|
|
1238
1232
|
}
|
|
1239
1233
|
|
|
1240
|
-
//
|
|
1241
|
-
//
|
|
1242
|
-
|
|
1234
|
+
// What the command decided rather than the project's files: which chains this
|
|
1235
|
+
// process drives, and whether the run is a dev run. A worker parses the same
|
|
1236
|
+
// files its supervisor did, so these are the only two it cannot arrive at on
|
|
1237
|
+
// its own.
|
|
1238
|
+
let withCommandFields = (json: JSON.t, ~chainIds, ~isDev) =>
|
|
1243
1239
|
switch json->JSON.Decode.object {
|
|
1244
1240
|
| Some(fields) => {
|
|
1245
1241
|
let narrowed = fields->Dict.copy
|
|
@@ -1247,6 +1243,7 @@ let withIsolatedChains = (json: JSON.t, ~chainIds) =>
|
|
|
1247
1243
|
"isolatedChains",
|
|
1248
1244
|
chainIds->S.reverseConvertToJsonOrThrow(S.array(ChainId.schema)),
|
|
1249
1245
|
)
|
|
1246
|
+
narrowed->Dict.set("isDev", JSON.Encode.bool(isDev))
|
|
1250
1247
|
JSON.Object(narrowed)
|
|
1251
1248
|
}
|
|
1252
1249
|
| None => JsError.throwWithMessage("Invalid indexer config: not an object")
|
package/src/Config.res.mjs
CHANGED
|
@@ -472,23 +472,8 @@ function getChain(config, chainId) {
|
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
function isPerChain(config) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
function logContext(config) {
|
|
479
|
-
let match = config.isolated;
|
|
480
|
-
let match$1 = ChainMap.keys(config.chainMap);
|
|
481
|
-
if (!match) {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
if (match$1.length !== 1) {
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
let chainId = match$1[0];
|
|
488
|
-
return Object.fromEntries([[
|
|
489
|
-
"chainId",
|
|
490
|
-
S$RescriptSchema.reverseConvertToJsonOrThrow(chainId, ChainId.schema)
|
|
491
|
-
]]);
|
|
475
|
+
let match = config.checkpointSequence;
|
|
476
|
+
return match !== "SharedAcrossChains";
|
|
492
477
|
}
|
|
493
478
|
|
|
494
479
|
function isolate(config, chainIds) {
|
|
@@ -928,13 +913,14 @@ function prime(json) {
|
|
|
928
913
|
cached.contents = undefined;
|
|
929
914
|
}
|
|
930
915
|
|
|
931
|
-
function
|
|
916
|
+
function withCommandFields(json, chainIds, isDev) {
|
|
932
917
|
let fields = Stdlib_JSON.Decode.object(json);
|
|
933
918
|
if (fields === undefined) {
|
|
934
919
|
return Stdlib_JsError.throwWithMessage("Invalid indexer config: not an object");
|
|
935
920
|
}
|
|
936
921
|
let narrowed = Object.assign({}, fields);
|
|
937
922
|
narrowed["isolatedChains"] = S$RescriptSchema.reverseConvertToJsonOrThrow(chainIds, S$RescriptSchema.array(ChainId.schema));
|
|
923
|
+
narrowed["isDev"] = isDev;
|
|
938
924
|
return narrowed;
|
|
939
925
|
}
|
|
940
926
|
|
|
@@ -1208,14 +1194,13 @@ export {
|
|
|
1208
1194
|
contractMappingOf,
|
|
1209
1195
|
getChain,
|
|
1210
1196
|
isPerChain,
|
|
1211
|
-
logContext,
|
|
1212
1197
|
isolate,
|
|
1213
1198
|
fromPublic,
|
|
1214
1199
|
normalizeUserAddress,
|
|
1215
1200
|
normalizeSimulateAddress,
|
|
1216
1201
|
getEventConfig,
|
|
1217
1202
|
prime,
|
|
1218
|
-
|
|
1203
|
+
withCommandFields,
|
|
1219
1204
|
getPublicConfigJson,
|
|
1220
1205
|
stripSensitiveData,
|
|
1221
1206
|
envioInfo,
|
package/src/CrossChainState.res
CHANGED
|
@@ -70,10 +70,10 @@ let isHoldingRealtime = (crossChainState: t) => crossChainState.holdRealtime
|
|
|
70
70
|
let hasArrivedAtHead = (crossChainState: t) =>
|
|
71
71
|
crossChainState.isCaughtUp ||
|
|
72
72
|
crossChainState.isRealtime || {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
let chainStates = crossChainState.chainStates->Dict.valuesToArray
|
|
74
|
+
chainStates->Utils.Array.notEmpty &&
|
|
75
|
+
chainStates->Array.every(ChainState.isReadyToEnterReorgThreshold)
|
|
76
|
+
}
|
|
77
77
|
|
|
78
78
|
// Resolve a chain's state by id. The id always comes from `chainIds`, which is
|
|
79
79
|
// derived from `chainStates`, so the entry is guaranteed present.
|
|
@@ -167,17 +167,23 @@ let createBatch = (
|
|
|
167
167
|
// holds the others back whatever process it runs in.
|
|
168
168
|
let isReadyToEnterReorgThreshold = (crossChainState: t, ~batch) =>
|
|
169
169
|
!crossChainState.holdRealtime &&
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
crossChainState.chainStates
|
|
171
|
+
->Dict.valuesToArray
|
|
172
|
+
->Array.every(cs => cs->ChainState.isReadyToEnterReorgThresholdAfterBatch(~batch))
|
|
173
173
|
|
|
174
|
+
// Said by each chain rather than once for the indexer: what crossing changes
|
|
175
|
+
// is a chain's own, and the chains of a split run cross in processes that can
|
|
176
|
+
// only speak for the ones they drive.
|
|
174
177
|
let enterReorgThreshold = (crossChainState: t) => {
|
|
175
|
-
Logging.info("Reorg threshold reached")
|
|
176
|
-
|
|
177
178
|
for i in 0 to crossChainState.chainIds->Array.length - 1 {
|
|
178
|
-
crossChainState
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
let cs = crossChainState->getChainState(crossChainState.chainIds->Array.getUnsafe(i))
|
|
180
|
+
// A chain whose end block sits below these blocks says nothing: crossing
|
|
181
|
+
// gives it nothing more to index, and it will never reach one of them.
|
|
182
|
+
let liftsCeiling = cs->ChainState.reorgThresholdLiftsCeiling
|
|
183
|
+
cs->ChainState.enterReorgThreshold
|
|
184
|
+
if liftsCeiling {
|
|
185
|
+
cs->ChainState.logger->Logging.childInfo(ChainState.reorgThresholdEntryMessage)
|
|
186
|
+
}
|
|
181
187
|
}
|
|
182
188
|
}
|
|
183
189
|
|
|
@@ -193,16 +199,16 @@ let applyBatchProgress = (crossChainState: t, ~batch: Batch.t, ~blockTimestampNa
|
|
|
193
199
|
for i in 0 to chainIds->Array.length - 1 {
|
|
194
200
|
let cs = crossChainState->getChainState(chainIds->Array.getUnsafe(i))
|
|
195
201
|
cs->ChainState.applyBatchProgress(~batch, ~blockTimestampName)
|
|
196
|
-
if !(cs->ChainState.
|
|
202
|
+
if !(cs->ChainState.hasCaughtUp) {
|
|
197
203
|
everyChainCaughtUp := false
|
|
198
204
|
}
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
crossChainState.isCaughtUp =
|
|
202
208
|
crossChainState.isCaughtUp ||
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
209
|
+
(!crossChainState.holdRealtime &&
|
|
210
|
+
crossChainState->nextItemIsNone &&
|
|
211
|
+
everyChainCaughtUp.contents)
|
|
206
212
|
}
|
|
207
213
|
|
|
208
214
|
// Every chain has buffered up to its head (or endblock) with nothing
|
|
@@ -248,7 +254,7 @@ let markCaughtUpOnResume = (crossChainState: t) => {
|
|
|
248
254
|
let everyChainCaughtUp = ref(crossChainState.chainIds->Array.length > 0)
|
|
249
255
|
for i in 0 to crossChainState.chainIds->Array.length - 1 {
|
|
250
256
|
let cs = crossChainState->getChainState(crossChainState.chainIds->Array.getUnsafe(i))
|
|
251
|
-
if !(cs->ChainState.
|
|
257
|
+
if !(cs->ChainState.hasCaughtUp) {
|
|
252
258
|
everyChainCaughtUp := false
|
|
253
259
|
}
|
|
254
260
|
}
|
|
@@ -263,13 +269,55 @@ let markCaughtUpOnResume = (crossChainState: t) => {
|
|
|
263
269
|
// and switches the indexer to realtime.
|
|
264
270
|
let markReady = (crossChainState: t, ~readyAt) => {
|
|
265
271
|
for i in 0 to crossChainState.chainIds->Array.length - 1 {
|
|
266
|
-
crossChainState
|
|
267
|
-
->
|
|
268
|
-
->ChainState.markReady(~readyAt)
|
|
272
|
+
let cs = crossChainState->getChainState(crossChainState.chainIds->Array.getUnsafe(i))
|
|
273
|
+
let wasReady = cs->ChainState.isReady
|
|
274
|
+
cs->ChainState.markReady(~readyAt)
|
|
275
|
+
|
|
276
|
+
// One line per chain, because `ready_at` is one column per chain: what the
|
|
277
|
+
// log says and what a reader finds in the row are the same fact.
|
|
278
|
+
if !wasReady {
|
|
279
|
+
cs
|
|
280
|
+
->ChainState.logger
|
|
281
|
+
->Logging.childInfo("Ready. Fully indexed for queries.")
|
|
282
|
+
}
|
|
269
283
|
}
|
|
270
284
|
crossChainState.isRealtime = true
|
|
271
285
|
}
|
|
272
286
|
|
|
287
|
+
// What a caught-up chain is waiting on before its process can finalize: the run
|
|
288
|
+
// holding the process back, or another chain it drives still behind. Read when
|
|
289
|
+
// the chain speaks, so "waiting" is said only while it is true.
|
|
290
|
+
let isWaitingOnOthers = (crossChainState: t, cs: ChainState.t) =>
|
|
291
|
+
crossChainState.holdRealtime ||
|
|
292
|
+
crossChainState.chainStates
|
|
293
|
+
->Dict.valuesToArray
|
|
294
|
+
->Array.some(other => other !== cs && !(other->ChainState.hasCaughtUp))
|
|
295
|
+
|
|
296
|
+
// Each chain that has just finished indexing, said once, by the chain it is
|
|
297
|
+
// about — so a chain that finishes early says so then, rather than when the
|
|
298
|
+
// last chain in its process catches up.
|
|
299
|
+
let reportFinished = (crossChainState: t) =>
|
|
300
|
+
crossChainState.chainStates
|
|
301
|
+
->Dict.valuesToArray
|
|
302
|
+
->Array.forEach(cs =>
|
|
303
|
+
switch cs->ChainState.takeFinished {
|
|
304
|
+
| Some(EndBlock(block)) =>
|
|
305
|
+
cs
|
|
306
|
+
->ChainState.logger
|
|
307
|
+
->Logging.childInfo({"msg": "Indexed to the end block. This chain is done.", "block": block})
|
|
308
|
+
| Some(Backfill(block)) =>
|
|
309
|
+
cs
|
|
310
|
+
->ChainState.logger
|
|
311
|
+
->Logging.childInfo({
|
|
312
|
+
"msg": crossChainState->isWaitingOnOthers(cs)
|
|
313
|
+
? "Finished backfill. Waiting for the other chains."
|
|
314
|
+
: "Finished backfill.",
|
|
315
|
+
"block": block,
|
|
316
|
+
})
|
|
317
|
+
| None => ()
|
|
318
|
+
}
|
|
319
|
+
)
|
|
320
|
+
|
|
273
321
|
// --- Fetch control. ---
|
|
274
322
|
|
|
275
323
|
// Chains ordered furthest-behind first by fetch-frontier progress, so the
|