envio 3.10.0 → 3.11.0-svm-alpha.1
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 +21 -4
- package/fuel.schema.json +21 -4
- package/index.d.ts +10 -6
- package/package.json +6 -6
- package/src/Batch.res +100 -78
- package/src/Batch.res.mjs +52 -46
- package/src/BatchProcessing.res +1 -11
- package/src/BatchProcessing.res.mjs +1 -4
- package/src/ChainState.res +46 -87
- package/src/ChainState.res.mjs +32 -66
- package/src/ChainState.resi +3 -0
- package/src/Config.res +131 -55
- package/src/Config.res.mjs +132 -69
- package/src/CrossChainState.res +39 -49
- package/src/CrossChainState.res.mjs +24 -22
- package/src/CrossChainState.resi +6 -13
- package/src/EffectState.res +13 -4
- package/src/EffectState.resi +7 -1
- package/src/EventConfigBuilder.res +14 -10
- package/src/EventConfigBuilder.res.mjs +6 -4
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +6 -6
- package/src/FetchState.res +14 -0
- package/src/FetchState.res.mjs +14 -0
- package/src/FinalizeBackfill.res +16 -12
- package/src/FinalizeBackfill.res.mjs +3 -3
- package/src/HandlerRegister.res +12 -11
- package/src/HandlerRegister.res.mjs +6 -5
- package/src/HistoryPolicy.res +46 -0
- package/src/HistoryPolicy.res.mjs +50 -0
- package/src/InMemoryStore.res +30 -32
- package/src/InMemoryStore.res.mjs +33 -28
- package/src/IndexerState.res +66 -45
- package/src/IndexerState.res.mjs +57 -29
- package/src/IndexerState.resi +8 -13
- package/src/Internal.res +24 -6
- package/src/Internal.res.mjs +9 -0
- package/src/LoadLayer.res +11 -4
- package/src/LoadLayer.res.mjs +8 -5
- package/src/Main.res +33 -25
- package/src/Main.res.mjs +25 -26
- package/src/Metrics.res +41 -1
- package/src/Metrics.res.mjs +25 -3
- package/src/Persistence.res +65 -17
- package/src/Persistence.res.mjs +23 -4
- package/src/PgStorage.res +192 -119
- package/src/PgStorage.res.mjs +130 -73
- package/src/PruneStaleHistory.res +9 -15
- package/src/PruneStaleHistory.res.mjs +11 -20
- package/src/Rollback.res +8 -14
- package/src/Rollback.res.mjs +4 -3
- package/src/SimulateItems.res +13 -6
- package/src/SimulateItems.res.mjs +7 -6
- package/src/Sink.res +7 -5
- package/src/Sink.res.mjs +4 -4
- package/src/TestIndexer.res +10 -10
- package/src/TestIndexer.res.mjs +11 -10
- package/src/UserContext.res +7 -4
- package/src/UserContext.res.mjs +5 -2
- package/src/Utils.res +9 -0
- package/src/Utils.res.mjs +9 -0
- package/src/Writing.res +34 -20
- package/src/Writing.res.mjs +15 -20
- package/src/bindings/ClickHouse.res +24 -8
- package/src/bindings/ClickHouse.res.mjs +20 -10
- package/src/bindings/ClickHouseSink.res +16 -5
- package/src/bindings/ClickHouseSink.res.mjs +3 -1
- package/src/db/CheckpointSequence.res +109 -0
- package/src/db/CheckpointSequence.res.mjs +99 -0
- package/src/db/EntityHistory.res +6 -5
- package/src/db/EntityHistory.res.mjs +5 -5
- package/src/db/Frontier.res +86 -0
- package/src/db/Frontier.res.mjs +126 -0
- package/src/db/InternalTable.res +112 -21
- package/src/db/InternalTable.res.mjs +95 -28
- package/src/db/RollbackFloors.res +34 -41
- package/src/db/RollbackFloors.res.mjs +27 -71
- package/src/sources/ChainSources.res +72 -0
- package/src/sources/ChainSources.res.mjs +55 -0
- package/src/sources/EvmHyperSyncSource.res +13 -23
- package/src/sources/EvmHyperSyncSource.res.mjs +11 -42
- package/src/sources/FuelHyperSyncSource.res +10 -18
- package/src/sources/FuelHyperSyncSource.res.mjs +8 -38
- package/src/sources/HyperSync.res +33 -0
- package/src/sources/HyperSync.res.mjs +32 -0
- package/src/sources/HyperSync.resi +17 -0
- package/src/sources/HyperSyncClient.res +3 -0
- package/src/sources/RequestStat.res +8 -1
- package/src/sources/Source.res +4 -3
- package/src/sources/SourceManager.res +30 -10
- package/src/sources/SourceManager.res.mjs +24 -7
- package/src/sources/SourceManager.resi +2 -0
- package/src/sources/StartBlockResolver.res +173 -0
- package/src/sources/StartBlockResolver.res.mjs +134 -0
- package/src/sources/Svm.res +0 -51
- package/src/sources/Svm.res.mjs +0 -46
- package/src/sources/SvmHyperSyncSource.res +20 -9
- package/src/sources/SvmHyperSyncSource.res.mjs +34 -12
- package/src/tui/Tui.res +56 -143
- package/src/tui/Tui.res.mjs +70 -166
- package/src/tui/components/TuiData.res +61 -16
- package/src/tui/components/TuiData.res.mjs +53 -15
- package/svm.schema.json +80 -73
- package/src/db/CheckpointBounds.res +0 -53
- package/src/db/CheckpointBounds.res.mjs +0 -44
package/evm.schema.json
CHANGED
|
@@ -494,10 +494,8 @@
|
|
|
494
494
|
"minimum": 0
|
|
495
495
|
},
|
|
496
496
|
"start_block": {
|
|
497
|
-
"description": "The block at which the indexer should start ingesting data",
|
|
498
|
-
"
|
|
499
|
-
"format": "uint64",
|
|
500
|
-
"minimum": 0
|
|
497
|
+
"description": "The block at which the indexer should start ingesting data, or \"latest\" to start from the chain's current head block when the indexer is first deployed. Once resolved, the concrete block is persisted and reused every time the indexer resumes normally (for example recovering from a crash), so downtime is backfilled instead of skipped. Running `envio start`/`dev` with -r (--restart) resets this like any other config change: \"latest\" resolves again, against the head at that time.",
|
|
498
|
+
"$ref": "#/$defs/StartBlock"
|
|
501
499
|
},
|
|
502
500
|
"end_block": {
|
|
503
501
|
"description": "The block at which the indexer should terminate.",
|
|
@@ -685,6 +683,25 @@
|
|
|
685
683
|
"url"
|
|
686
684
|
]
|
|
687
685
|
},
|
|
686
|
+
"StartBlock": {
|
|
687
|
+
"description": "A chain's configured start block: either a concrete block number or the\nliteral \"latest\". Config parsing never touches the network, so `Latest`\nstays unresolved here — it's resolved once at runtime, right before the\nindexer's first-ever persisted state is written, and never re-resolved\non a normal resume (see packages/envio/src/sources/StartBlockResolver.res).\nNote: this repo's `-r`/`--restart` CLI flag wipes the DB and re-deploys\nfrom scratch, so it re-resolves \"latest\" too — \"resume\" here means the\nopposite: recovering from a crash or process restart without `-r`.",
|
|
688
|
+
"anyOf": [
|
|
689
|
+
{
|
|
690
|
+
"type": "integer",
|
|
691
|
+
"format": "uint64",
|
|
692
|
+
"minimum": 0
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
"$ref": "#/$defs/StartBlockTag"
|
|
696
|
+
}
|
|
697
|
+
]
|
|
698
|
+
},
|
|
699
|
+
"StartBlockTag": {
|
|
700
|
+
"type": "string",
|
|
701
|
+
"enum": [
|
|
702
|
+
"latest"
|
|
703
|
+
]
|
|
704
|
+
},
|
|
688
705
|
"ChainContract": {
|
|
689
706
|
"type": "object",
|
|
690
707
|
"properties": {
|
package/fuel.schema.json
CHANGED
|
@@ -328,10 +328,8 @@
|
|
|
328
328
|
]
|
|
329
329
|
},
|
|
330
330
|
"start_block": {
|
|
331
|
-
"description": "The block at which the indexer should start ingesting data",
|
|
332
|
-
"
|
|
333
|
-
"format": "uint64",
|
|
334
|
-
"minimum": 0
|
|
331
|
+
"description": "The block at which the indexer should start ingesting data, or \"latest\" to start from the chain's current head block when the indexer is first deployed. Once resolved, the concrete block is persisted and reused every time the indexer resumes normally (for example recovering from a crash), so downtime is backfilled instead of skipped. Running `envio start`/`dev` with -r (--restart) resets this like any other config change: \"latest\" resolves again, against the head at that time.",
|
|
332
|
+
"$ref": "#/$defs/StartBlock"
|
|
335
333
|
},
|
|
336
334
|
"end_block": {
|
|
337
335
|
"description": "The block at which the indexer should terminate.",
|
|
@@ -388,6 +386,25 @@
|
|
|
388
386
|
"start_block"
|
|
389
387
|
]
|
|
390
388
|
},
|
|
389
|
+
"StartBlock": {
|
|
390
|
+
"description": "A chain's configured start block: either a concrete block number or the\nliteral \"latest\". Config parsing never touches the network, so `Latest`\nstays unresolved here — it's resolved once at runtime, right before the\nindexer's first-ever persisted state is written, and never re-resolved\non a normal resume (see packages/envio/src/sources/StartBlockResolver.res).\nNote: this repo's `-r`/`--restart` CLI flag wipes the DB and re-deploys\nfrom scratch, so it re-resolves \"latest\" too — \"resume\" here means the\nopposite: recovering from a crash or process restart without `-r`.",
|
|
391
|
+
"anyOf": [
|
|
392
|
+
{
|
|
393
|
+
"type": "integer",
|
|
394
|
+
"format": "uint64",
|
|
395
|
+
"minimum": 0
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"$ref": "#/$defs/StartBlockTag"
|
|
399
|
+
}
|
|
400
|
+
]
|
|
401
|
+
},
|
|
402
|
+
"StartBlockTag": {
|
|
403
|
+
"type": "string",
|
|
404
|
+
"enum": [
|
|
405
|
+
"latest"
|
|
406
|
+
]
|
|
407
|
+
},
|
|
391
408
|
"HyperfuelConfig": {
|
|
392
409
|
"type": "object",
|
|
393
410
|
"properties": {
|
package/index.d.ts
CHANGED
|
@@ -1216,6 +1216,9 @@ export type SvmAllTransactionFields = {
|
|
|
1216
1216
|
readonly err: string | undefined;
|
|
1217
1217
|
readonly fee: bigint;
|
|
1218
1218
|
readonly computeUnitsConsumed: bigint | undefined;
|
|
1219
|
+
/** Every account the transaction resolves to: the static keys, then the
|
|
1220
|
+
* address lookup tables' writable then readonly addresses. A transaction's
|
|
1221
|
+
* account indexes address this list. */
|
|
1219
1222
|
readonly accountKeys: readonly string[];
|
|
1220
1223
|
readonly recentBlockhash: string;
|
|
1221
1224
|
readonly version: string | undefined;
|
|
@@ -1377,7 +1380,7 @@ type SvmNamedAccounts<
|
|
|
1377
1380
|
Acc extends Readonly<Record<string, unknown>>,
|
|
1378
1381
|
Fields extends SvmFieldsSelection,
|
|
1379
1382
|
> = {
|
|
1380
|
-
readonly [K in keyof Acc
|
|
1383
|
+
readonly [K in keyof Acc]: SvmInstructionAccount<Fields, K & string>;
|
|
1381
1384
|
};
|
|
1382
1385
|
|
|
1383
1386
|
/** The parent transaction of a {@link SvmInstruction}, narrowed to the
|
|
@@ -1524,8 +1527,8 @@ export type SvmOnInstructionOptions<
|
|
|
1524
1527
|
/** Program name as declared under `chains[].programs[].name` in
|
|
1525
1528
|
* `config.yaml`. */
|
|
1526
1529
|
readonly program: P;
|
|
1527
|
-
/** Instruction name
|
|
1528
|
-
* `chains[].programs[].instructions[].name`
|
|
1530
|
+
/** Instruction name from the program's IDL, or from
|
|
1531
|
+
* `chains[].programs[].instructions[].name` when the layout is inline. */
|
|
1529
1532
|
readonly instruction: I;
|
|
1530
1533
|
readonly fields?: Fields & SvmFieldsLiteralCheck<Fields>;
|
|
1531
1534
|
readonly where?: SvmOnInstructionWhere<SvmAccountsOf<P, I>>;
|
|
@@ -1768,9 +1771,10 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
|
|
|
1768
1771
|
}
|
|
1769
1772
|
? {
|
|
1770
1773
|
/**
|
|
1771
|
-
* Register an instruction handler.
|
|
1772
|
-
*
|
|
1773
|
-
* Handler `fields` is the only
|
|
1774
|
+
* Register an instruction handler. `program` and `instruction`
|
|
1775
|
+
* name an entry from the IDL or YAML. Dispatch uses that
|
|
1776
|
+
* instruction's discriminator. Handler `fields` is the only
|
|
1777
|
+
* source of payload selection.
|
|
1774
1778
|
*/
|
|
1775
1779
|
readonly onInstruction: <
|
|
1776
1780
|
P extends keyof Programs & string,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0-svm-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
|
|
6
6
|
"bin": "./bin.mjs",
|
|
@@ -68,10 +68,10 @@
|
|
|
68
68
|
"tsx": "4.21.0"
|
|
69
69
|
},
|
|
70
70
|
"optionalDependencies": {
|
|
71
|
-
"envio-linux-x64": "3.
|
|
72
|
-
"envio-linux-x64-musl": "3.
|
|
73
|
-
"envio-linux-arm64": "3.
|
|
74
|
-
"envio-darwin-x64": "3.
|
|
75
|
-
"envio-darwin-arm64": "3.
|
|
71
|
+
"envio-linux-x64": "3.11.0-svm-alpha.1",
|
|
72
|
+
"envio-linux-x64-musl": "3.11.0-svm-alpha.1",
|
|
73
|
+
"envio-linux-arm64": "3.11.0-svm-alpha.1",
|
|
74
|
+
"envio-darwin-x64": "3.11.0-svm-alpha.1",
|
|
75
|
+
"envio-darwin-arm64": "3.11.0-svm-alpha.1"
|
|
76
76
|
}
|
|
77
77
|
}
|
package/src/Batch.res
CHANGED
|
@@ -34,24 +34,32 @@ type t = {
|
|
|
34
34
|
totalBatchSize: int,
|
|
35
35
|
items: array<Internal.item>,
|
|
36
36
|
progressedChainsById: dict<chainAfterBatch>,
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
37
|
+
// Whether the batch's rows get history. Writes never merge across a change in
|
|
38
|
+
// it, so a single write can't mix the two.
|
|
39
|
+
history: HistoryPolicy.t,
|
|
40
40
|
// Unnest-like checkpoint fields:
|
|
41
41
|
checkpointIds: array<bigint>,
|
|
42
42
|
checkpointChainIds: array<ChainId.t>,
|
|
43
43
|
checkpointBlockNumbers: array<int>,
|
|
44
44
|
checkpointBlockHashes: array<Null.t<string>>,
|
|
45
|
+
// Items the checkpoint carries, which is what indexes `items`.
|
|
46
|
+
checkpointItemsCount: array<int>,
|
|
47
|
+
// Logs the checkpoint carries: one log routed to several registrations is one
|
|
48
|
+
// event, however many items it made.
|
|
45
49
|
checkpointEventsProcessed: array<int>,
|
|
46
50
|
registeredAddresses: array<AddressRows.staged>,
|
|
47
51
|
}
|
|
48
52
|
|
|
53
|
+
// What a chain contributed to the batch: items taken off its buffer, and the
|
|
54
|
+
// logs behind them.
|
|
55
|
+
type chainBatchCounts = {size: int, eventsProcessed: int}
|
|
56
|
+
|
|
49
57
|
let getProgressedChainsById = {
|
|
50
58
|
let getChainAfterBatchIfProgressed = (
|
|
51
59
|
~chainBeforeBatch: chainBeforeBatch,
|
|
52
60
|
~progressBlockNumberAfterBatch,
|
|
53
61
|
~fetchStateAfterBatch,
|
|
54
|
-
~
|
|
62
|
+
~counts: chainBatchCounts,
|
|
55
63
|
) => {
|
|
56
64
|
// The check is sufficient, since we guarantee to include a full block in a batch
|
|
57
65
|
// Also, this might be true even if batchSize is 0,
|
|
@@ -60,10 +68,11 @@ let getProgressedChainsById = {
|
|
|
60
68
|
Some(
|
|
61
69
|
(
|
|
62
70
|
{
|
|
63
|
-
batchSize,
|
|
71
|
+
batchSize: counts.size,
|
|
64
72
|
progressBlockNumber: progressBlockNumberAfterBatch,
|
|
65
73
|
sourceBlockNumber: chainBeforeBatch.sourceBlockNumber,
|
|
66
|
-
totalEventsProcessed: chainBeforeBatch.totalEventsProcessed +.
|
|
74
|
+
totalEventsProcessed: chainBeforeBatch.totalEventsProcessed +.
|
|
75
|
+
counts.eventsProcessed->Int.toFloat,
|
|
67
76
|
fetchState: fetchStateAfterBatch,
|
|
68
77
|
isProgressAtHeadWhenBatchCreated: progressBlockNumberAfterBatch >=
|
|
69
78
|
chainBeforeBatch.sourceBlockNumber - chainBeforeBatch.chainConfig.blockLag,
|
|
@@ -77,7 +86,7 @@ let getProgressedChainsById = {
|
|
|
77
86
|
|
|
78
87
|
(
|
|
79
88
|
~chainsBeforeBatch: dict<chainBeforeBatch>,
|
|
80
|
-
~
|
|
89
|
+
~countsPerChain: dict<chainBatchCounts>,
|
|
81
90
|
~progressBlockNumberPerChain: dict<int>,
|
|
82
91
|
) => {
|
|
83
92
|
let progressedChainsById = Dict.make()
|
|
@@ -98,14 +107,14 @@ let getProgressedChainsById = {
|
|
|
98
107
|
| None => chainBeforeBatch.progressBlockNumber
|
|
99
108
|
}
|
|
100
109
|
|
|
101
|
-
switch switch
|
|
110
|
+
switch switch countsPerChain->Utils.Dict.dangerouslyGetNonOption(
|
|
102
111
|
fetchState.chainId->ChainId.toString,
|
|
103
112
|
) {
|
|
104
|
-
| Some(
|
|
105
|
-
let leftItems = fetchState.buffer->Array.slice(~start=
|
|
113
|
+
| Some(counts) =>
|
|
114
|
+
let leftItems = fetchState.buffer->Array.slice(~start=counts.size)
|
|
106
115
|
getChainAfterBatchIfProgressed(
|
|
107
116
|
~chainBeforeBatch,
|
|
108
|
-
~
|
|
117
|
+
~counts,
|
|
109
118
|
~fetchStateAfterBatch=fetchState->FetchState.updateInternal(~mutItems=leftItems),
|
|
110
119
|
~progressBlockNumberAfterBatch,
|
|
111
120
|
)
|
|
@@ -113,7 +122,7 @@ let getProgressedChainsById = {
|
|
|
113
122
|
| None =>
|
|
114
123
|
getChainAfterBatchIfProgressed(
|
|
115
124
|
~chainBeforeBatch,
|
|
116
|
-
~
|
|
125
|
+
~counts={size: 0, eventsProcessed: 0},
|
|
117
126
|
~fetchStateAfterBatch=chainBeforeBatch.fetchState,
|
|
118
127
|
~progressBlockNumberAfterBatch,
|
|
119
128
|
)
|
|
@@ -146,7 +155,7 @@ let seekFirstAbove = (blockNumbers: array<int>, blockNumber) => {
|
|
|
146
155
|
|
|
147
156
|
@inline
|
|
148
157
|
let addReorgCheckpoints = (
|
|
149
|
-
~
|
|
158
|
+
~cursor,
|
|
150
159
|
~scannedHashes: reorgHashSnapshot,
|
|
151
160
|
~shouldRollbackOnReorg,
|
|
152
161
|
~fromBlockExclusive,
|
|
@@ -156,10 +165,10 @@ let addReorgCheckpoints = (
|
|
|
156
165
|
~mutCheckpointChainIds,
|
|
157
166
|
~mutCheckpointBlockNumbers,
|
|
158
167
|
~mutCheckpointBlockHashes,
|
|
168
|
+
~mutCheckpointItemsCount,
|
|
159
169
|
~mutCheckpointEventsProcessed,
|
|
160
170
|
) => {
|
|
161
171
|
if shouldRollbackOnReorg {
|
|
162
|
-
let prevCheckpointId = ref(prevCheckpointId)
|
|
163
172
|
// The snapshot already holds only in-threshold scanned hashes, ascending,
|
|
164
173
|
// so seeking to the gap's lower bound gives the gap checkpoints without
|
|
165
174
|
// rescanning the whole snapshot for every gap in the batch.
|
|
@@ -172,37 +181,30 @@ let addReorgCheckpoints = (
|
|
|
172
181
|
scannedHashes.hashByBlockNumber
|
|
173
182
|
->Utils.Dict.dangerouslyGetByIntNonOption(blockNumber)
|
|
174
183
|
->Option.getUnsafe
|
|
175
|
-
let checkpointId =
|
|
176
|
-
prevCheckpointId := checkpointId
|
|
184
|
+
let checkpointId = cursor->CheckpointSequence.next(~chainId)
|
|
177
185
|
|
|
178
186
|
mutCheckpointIds->Array.push(checkpointId)
|
|
179
187
|
mutCheckpointChainIds->Array.push(chainId)
|
|
180
188
|
mutCheckpointBlockNumbers->Array.push(blockNumber)
|
|
181
189
|
mutCheckpointBlockHashes->Array.push(Null.Value(hash))
|
|
190
|
+
mutCheckpointItemsCount->Array.push(0)
|
|
182
191
|
mutCheckpointEventsProcessed->Array.push(0)
|
|
183
192
|
|
|
184
193
|
idx := idx.contents + 1
|
|
185
194
|
}
|
|
186
|
-
prevCheckpointId.contents
|
|
187
|
-
} else {
|
|
188
|
-
prevCheckpointId
|
|
189
195
|
}
|
|
190
196
|
}
|
|
191
197
|
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// interleave freely *across* chains, which is exactly why that predicate can't
|
|
200
|
-
// be the id bound alone.
|
|
201
|
-
let prepareBatch = (
|
|
202
|
-
~checkpointIdBeforeBatch,
|
|
198
|
+
// Within a chain, ids ascend with block order, and rollback preserves that by
|
|
199
|
+
// deleting the chain's ids above its target before any higher one is allocated.
|
|
200
|
+
// Every rollback deletes by `id > target`, which is only the stale suffix while
|
|
201
|
+
// ids and blocks agree on order within each chain.
|
|
202
|
+
let make = (
|
|
203
|
+
~sequence: CheckpointSequence.t,
|
|
204
|
+
~frontier: Frontier.t,
|
|
203
205
|
~chainsBeforeBatch: dict<chainBeforeBatch>,
|
|
204
206
|
~batchSizeTarget,
|
|
205
|
-
~
|
|
207
|
+
~history,
|
|
206
208
|
) => {
|
|
207
209
|
let preparedFetchStates =
|
|
208
210
|
chainsBeforeBatch
|
|
@@ -214,8 +216,8 @@ let prepareBatch = (
|
|
|
214
216
|
let preparedNumber = preparedFetchStates->Array.length
|
|
215
217
|
let totalBatchSize = ref(0)
|
|
216
218
|
|
|
217
|
-
let
|
|
218
|
-
let
|
|
219
|
+
let cursor = sequence->CheckpointSequence.cursor(~frontier)
|
|
220
|
+
let mutCountsPerChain = Dict.make()
|
|
219
221
|
let mutProgressBlockNumberPerChain = Dict.make()
|
|
220
222
|
|
|
221
223
|
let items = []
|
|
@@ -223,6 +225,7 @@ let prepareBatch = (
|
|
|
223
225
|
let checkpointChainIds = []
|
|
224
226
|
let checkpointBlockNumbers = []
|
|
225
227
|
let checkpointBlockHashes = []
|
|
228
|
+
let checkpointItemsCount = []
|
|
226
229
|
let checkpointEventsProcessed = []
|
|
227
230
|
|
|
228
231
|
// Accumulate items for all actively indexing chains
|
|
@@ -241,29 +244,38 @@ let prepareBatch = (
|
|
|
241
244
|
->Option.getUnsafe
|
|
242
245
|
|
|
243
246
|
let prevBlockNumber = ref(chainBeforeBatch.progressBlockNumber)
|
|
247
|
+
let chainEventsProcessed = ref(0)
|
|
244
248
|
if chainBatchSize > 0 {
|
|
245
249
|
for idx in 0 to chainBatchSize - 1 {
|
|
246
250
|
let item = fetchState.buffer->Array.getUnsafe(idx)
|
|
247
251
|
let blockNumber = item->Internal.getItemBlockNumber
|
|
252
|
+
// The buffer is sorted, so a log's items are consecutive: the first of
|
|
253
|
+
// them is the only one that counts as an event.
|
|
254
|
+
let isNewEvent =
|
|
255
|
+
idx === 0 ||
|
|
256
|
+
!(fetchState.buffer->Array.getUnsafe(idx - 1)->FetchState.isSameLog(item))
|
|
257
|
+
if isNewEvent {
|
|
258
|
+
chainEventsProcessed := chainEventsProcessed.contents + 1
|
|
259
|
+
}
|
|
248
260
|
|
|
249
261
|
// Every new block we should create a new checkpoint
|
|
250
262
|
if blockNumber !== prevBlockNumber.contents {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
let checkpointId =
|
|
263
|
+
addReorgCheckpoints(
|
|
264
|
+
~chainId=fetchState.chainId,
|
|
265
|
+
~scannedHashes=chainBeforeBatch.scannedHashes,
|
|
266
|
+
~shouldRollbackOnReorg=chainBeforeBatch.shouldRollbackOnReorg,
|
|
267
|
+
~cursor,
|
|
268
|
+
~fromBlockExclusive=prevBlockNumber.contents,
|
|
269
|
+
~toBlockExclusive=blockNumber,
|
|
270
|
+
~mutCheckpointIds=checkpointIds,
|
|
271
|
+
~mutCheckpointChainIds=checkpointChainIds,
|
|
272
|
+
~mutCheckpointBlockNumbers=checkpointBlockNumbers,
|
|
273
|
+
~mutCheckpointBlockHashes=checkpointBlockHashes,
|
|
274
|
+
~mutCheckpointItemsCount=checkpointItemsCount,
|
|
275
|
+
~mutCheckpointEventsProcessed=checkpointEventsProcessed,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
let checkpointId = cursor->CheckpointSequence.next(~chainId=fetchState.chainId)
|
|
267
279
|
|
|
268
280
|
checkpointIds->Array.push(checkpointId)->ignore
|
|
269
281
|
checkpointChainIds->Array.push(fetchState.chainId)->ignore
|
|
@@ -278,41 +290,49 @@ let prepareBatch = (
|
|
|
278
290
|
},
|
|
279
291
|
)
|
|
280
292
|
->ignore
|
|
293
|
+
checkpointItemsCount->Array.push(1)->ignore
|
|
281
294
|
checkpointEventsProcessed->Array.push(1)->ignore
|
|
282
295
|
|
|
283
296
|
prevBlockNumber := blockNumber
|
|
284
|
-
prevCheckpointId := checkpointId
|
|
285
297
|
} else {
|
|
286
|
-
let lastIndex =
|
|
287
|
-
|
|
288
|
-
->Array.setUnsafe(lastIndex,
|
|
298
|
+
let lastIndex = checkpointItemsCount->Array.length - 1
|
|
299
|
+
checkpointItemsCount
|
|
300
|
+
->Array.setUnsafe(lastIndex, checkpointItemsCount->Array.getUnsafe(lastIndex) + 1)
|
|
289
301
|
->ignore
|
|
302
|
+
if isNewEvent {
|
|
303
|
+
checkpointEventsProcessed
|
|
304
|
+
->Array.setUnsafe(lastIndex, checkpointEventsProcessed->Array.getUnsafe(lastIndex) + 1)
|
|
305
|
+
->ignore
|
|
306
|
+
}
|
|
290
307
|
}
|
|
291
308
|
|
|
292
309
|
items->Array.push(item)->ignore
|
|
293
310
|
}
|
|
294
311
|
|
|
295
312
|
totalBatchSize := totalBatchSize.contents + chainBatchSize
|
|
296
|
-
|
|
313
|
+
mutCountsPerChain->ChainId.Dict.set(
|
|
314
|
+
fetchState.chainId,
|
|
315
|
+
{size: chainBatchSize, eventsProcessed: chainEventsProcessed.contents},
|
|
316
|
+
)
|
|
297
317
|
}
|
|
298
318
|
|
|
299
319
|
let progressBlockNumberAfterBatch =
|
|
300
320
|
fetchState->FetchState.getProgressBlockNumberAt(~index=chainBatchSize)
|
|
301
321
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
322
|
+
addReorgCheckpoints(
|
|
323
|
+
~chainId=fetchState.chainId,
|
|
324
|
+
~scannedHashes=chainBeforeBatch.scannedHashes,
|
|
325
|
+
~shouldRollbackOnReorg=chainBeforeBatch.shouldRollbackOnReorg,
|
|
326
|
+
~cursor,
|
|
327
|
+
~fromBlockExclusive=prevBlockNumber.contents,
|
|
328
|
+
~toBlockExclusive=progressBlockNumberAfterBatch + 1, // Make it inclusive
|
|
329
|
+
~mutCheckpointIds=checkpointIds,
|
|
330
|
+
~mutCheckpointChainIds=checkpointChainIds,
|
|
331
|
+
~mutCheckpointBlockNumbers=checkpointBlockNumbers,
|
|
332
|
+
~mutCheckpointBlockHashes=checkpointBlockHashes,
|
|
333
|
+
~mutCheckpointItemsCount=checkpointItemsCount,
|
|
334
|
+
~mutCheckpointEventsProcessed=checkpointEventsProcessed,
|
|
335
|
+
)
|
|
316
336
|
|
|
317
337
|
mutProgressBlockNumberPerChain->ChainId.Dict.set(
|
|
318
338
|
fetchState.chainId,
|
|
@@ -327,26 +347,28 @@ let prepareBatch = (
|
|
|
327
347
|
items,
|
|
328
348
|
progressedChainsById: getProgressedChainsById(
|
|
329
349
|
~chainsBeforeBatch,
|
|
330
|
-
~
|
|
350
|
+
~countsPerChain=mutCountsPerChain,
|
|
331
351
|
~progressBlockNumberPerChain=mutProgressBlockNumberPerChain,
|
|
332
352
|
),
|
|
333
|
-
|
|
353
|
+
history,
|
|
334
354
|
checkpointIds,
|
|
335
355
|
checkpointChainIds,
|
|
336
356
|
checkpointBlockNumbers,
|
|
337
357
|
checkpointBlockHashes,
|
|
358
|
+
checkpointItemsCount,
|
|
338
359
|
checkpointEventsProcessed,
|
|
339
360
|
registeredAddresses: [],
|
|
340
361
|
}
|
|
341
362
|
}
|
|
342
363
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
)
|
|
349
|
-
|
|
364
|
+
// Where the batch leaves each chain it handed ids to. Ids ascend within a
|
|
365
|
+
// chain, so the last one seen per chain is its highest.
|
|
366
|
+
let checkpointFrontier = (batch: t): Frontier.t => {
|
|
367
|
+
let frontier = Frontier.empty()
|
|
368
|
+
batch.checkpointChainIds->Array.forEachWithIndex((chainId, index) =>
|
|
369
|
+
frontier->Frontier.set(chainId, batch.checkpointIds->Array.getUnsafe(index))
|
|
370
|
+
)
|
|
371
|
+
frontier
|
|
350
372
|
}
|
|
351
373
|
|
|
352
374
|
let findFirstEventBlockNumber = (batch: t, ~chainId) => {
|
|
@@ -357,7 +379,7 @@ let findFirstEventBlockNumber = (batch: t, ~chainId) => {
|
|
|
357
379
|
let checkpointChainId = batch.checkpointChainIds->Array.getUnsafe(idx.contents)
|
|
358
380
|
if (
|
|
359
381
|
checkpointChainId === chainId &&
|
|
360
|
-
batch.
|
|
382
|
+
batch.checkpointItemsCount->Array.getUnsafe(idx.contents) > 0
|
|
361
383
|
) {
|
|
362
384
|
result := Some(batch.checkpointBlockNumbers->Array.getUnsafe(idx.contents))
|
|
363
385
|
} else {
|