envio 3.11.0 → 3.12.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/index.d.ts +3 -0
- package/package.json +6 -6
- package/src/Batch.res +111 -78
- package/src/Batch.res.mjs +53 -46
- package/src/BatchProcessing.res +1 -11
- package/src/BatchProcessing.res.mjs +1 -4
- package/src/ChainFetching.res +7 -3
- package/src/ChainFetching.res.mjs +1 -1
- package/src/ChainState.res +82 -20
- package/src/ChainState.res.mjs +51 -13
- package/src/ChainState.resi +6 -1
- package/src/Config.res +58 -37
- package/src/Config.res.mjs +63 -53
- package/src/CrossChainState.res +50 -53
- package/src/CrossChainState.res.mjs +25 -23
- package/src/CrossChainState.resi +6 -13
- package/src/EffectState.res +13 -4
- package/src/EffectState.resi +7 -1
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +6 -6
- package/src/FetchState.res +65 -46
- package/src/FetchState.res.mjs +68 -36
- package/src/FinalizeBackfill.res +16 -12
- package/src/FinalizeBackfill.res.mjs +3 -3
- 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/InMemoryTable.res +155 -67
- package/src/InMemoryTable.res.mjs +151 -60
- package/src/IndexerState.res +66 -45
- package/src/IndexerState.res.mjs +57 -29
- package/src/IndexerState.resi +8 -13
- package/src/Internal.res +4 -2
- package/src/LoadLayer.res +68 -38
- package/src/LoadLayer.res.mjs +50 -64
- package/src/LoadLayer.resi +1 -1
- package/src/Main.res +25 -24
- package/src/Main.res.mjs +24 -25
- package/src/Metrics.res +49 -1
- package/src/Metrics.res.mjs +26 -3
- package/src/Persistence.res +55 -16
- package/src/Persistence.res.mjs +18 -3
- package/src/PgStorage.res +286 -180
- package/src/PgStorage.res.mjs +209 -122
- package/src/PruneStaleHistory.res +9 -15
- package/src/PruneStaleHistory.res.mjs +11 -20
- package/src/Rollback.res +9 -14
- package/src/Rollback.res.mjs +5 -3
- package/src/Sink.res +7 -5
- package/src/Sink.res.mjs +4 -4
- package/src/Staging.res +298 -0
- package/src/Staging.res.mjs +257 -0
- package/src/TestIndexer.res +14 -30
- package/src/TestIndexer.res.mjs +11 -9
- package/src/UserContext.res +20 -36
- package/src/UserContext.res.mjs +6 -9
- package/src/Utils.res +10 -4
- package/src/Utils.res.mjs +16 -16
- package/src/Writing.res +34 -20
- package/src/Writing.res.mjs +15 -20
- package/src/bindings/ClickHouse.res +41 -34
- package/src/bindings/ClickHouse.res.mjs +36 -30
- package/src/bindings/ClickHouseSink.res +45 -186
- package/src/bindings/ClickHouseSink.res.mjs +21 -174
- package/src/db/CheckpointSequence.res +109 -0
- package/src/db/CheckpointSequence.res.mjs +99 -0
- package/src/db/EntityFilter.res +487 -275
- package/src/db/EntityFilter.res.mjs +557 -309
- 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 +145 -27
- package/src/db/InternalTable.res.mjs +115 -29
- package/src/db/RollbackFloors.res +34 -41
- package/src/db/RollbackFloors.res.mjs +27 -71
- package/src/db/Table.res +21 -6
- package/src/db/Table.res.mjs +13 -4
- package/src/sources/BlockStore.res +8 -0
- package/src/sources/EvmHyperSyncSource.res +5 -1
- package/src/sources/EvmHyperSyncSource.res.mjs +4 -3
- package/src/sources/FuelHyperSyncSource.res +1 -0
- package/src/sources/FuelHyperSyncSource.res.mjs +1 -1
- package/src/sources/HyperSync.res +6 -0
- package/src/sources/HyperSync.res.mjs +5 -2
- package/src/sources/HyperSync.resi +2 -0
- package/src/sources/HyperSyncClient.res +6 -0
- package/src/sources/HyperSyncSSE.res +1 -1
- package/src/sources/HyperSyncSSE.res.mjs +4 -10
- package/src/sources/RequestStat.res +8 -1
- package/src/sources/RpcSource.res +1 -0
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/SimulateSource.res +1 -0
- package/src/sources/SimulateSource.res.mjs +1 -1
- package/src/sources/Source.res +11 -3
- package/src/sources/SourceManager.res +34 -13
- package/src/sources/SourceManager.res.mjs +26 -9
- package/src/sources/SourceManager.resi +2 -0
- package/src/sources/SvmHyperSyncClient.res +5 -0
- package/src/sources/SvmHyperSyncSource.res +3 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -2
- 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 +0 -7
- package/src/db/CheckpointBounds.res +0 -53
- package/src/db/CheckpointBounds.res.mjs +0 -44
|
@@ -44,12 +44,12 @@ function make(param) {
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
};
|
|
47
|
-
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, knownHeight, param, selection, itemsTarget, retry, param$1) => {
|
|
47
|
+
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, includeAllBlocks, knownHeight, param, selection, itemsTarget, retry, param$1) => {
|
|
48
48
|
let totalTimeRef = Performance.now();
|
|
49
49
|
let startFetchingBatchTimeRef = Performance.now();
|
|
50
50
|
let pageUnsafe;
|
|
51
51
|
try {
|
|
52
|
-
pageUnsafe = await HyperSync.GetLogs.query(client, fromBlock, toBlock, itemsTarget, selection.onEventRegistrations.map(reg => reg.index), addressSet, selection.clientFilteredContracts);
|
|
52
|
+
pageUnsafe = await HyperSync.GetLogs.query(client, fromBlock, toBlock, itemsTarget, selection.onEventRegistrations.map(reg => reg.index), addressSet, selection.clientFilteredContracts, includeAllBlocks);
|
|
53
53
|
} catch (raw_exn) {
|
|
54
54
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
55
55
|
if (exn.RE_EXN_ID === HyperSync.GetLogs.$$Error) {
|
|
@@ -100,7 +100,8 @@ function make(param) {
|
|
|
100
100
|
let pageFetchTime = Performance.secondsSince(startFetchingBatchTimeRef);
|
|
101
101
|
let requestStats = [{
|
|
102
102
|
method: "getLogs",
|
|
103
|
-
seconds: pageFetchTime
|
|
103
|
+
seconds: pageFetchTime,
|
|
104
|
+
responseBlocks: pageUnsafe.responseBlocks
|
|
104
105
|
}];
|
|
105
106
|
let knownHeight$1 = pageUnsafe.archiveHeight;
|
|
106
107
|
let heighestBlockQueried = pageUnsafe.nextBlock - 1 | 0;
|
|
@@ -28,7 +28,7 @@ function make(param) {
|
|
|
28
28
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
29
29
|
client = ErrorHandling.mkLogAndRaise(undefined, "Failed to instantiate the HyperFuel client", exn);
|
|
30
30
|
}
|
|
31
|
-
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, knownHeight, param, selection, param$
|
|
31
|
+
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, param, knownHeight, param$1, selection, param$2, retry, logger) => {
|
|
32
32
|
let totalTimeRef = Performance.now();
|
|
33
33
|
let startFetchingBatchTimeRef = Performance.now();
|
|
34
34
|
let pageUnsafe;
|
|
@@ -90,6 +90,7 @@ type logsQueryPage = {
|
|
|
90
90
|
items: array<HyperSyncClient.EventItems.item>,
|
|
91
91
|
nextBlock: int,
|
|
92
92
|
archiveHeight: int,
|
|
93
|
+
responseBlocks: int,
|
|
93
94
|
// Page store owning this page's raw transactions.
|
|
94
95
|
transactionStore: TransactionStore.t,
|
|
95
96
|
// Page store owning this page's raw blocks.
|
|
@@ -136,6 +137,7 @@ module GetLogs = {
|
|
|
136
137
|
~registrationIndexes,
|
|
137
138
|
~addressSet,
|
|
138
139
|
~clientFilteredContracts,
|
|
140
|
+
~includeAllBlocks,
|
|
139
141
|
): logsQueryPage => {
|
|
140
142
|
let query: HyperSyncClient.EventItems.query = {
|
|
141
143
|
fromBlock,
|
|
@@ -143,6 +145,9 @@ module GetLogs = {
|
|
|
143
145
|
?maxNumLogs,
|
|
144
146
|
registrationIndexes,
|
|
145
147
|
clientFilteredContracts,
|
|
148
|
+
// Absent rather than false, so a range that wants only the blocks its
|
|
149
|
+
// logs came from sends the query it always sent.
|
|
150
|
+
includeAllBlocks: ?(includeAllBlocks ? Some(true) : None),
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
let (res, transactionStore, blockStore) = switch await client.getEventItems(
|
|
@@ -165,6 +170,7 @@ module GetLogs = {
|
|
|
165
170
|
{
|
|
166
171
|
items: res.items,
|
|
167
172
|
nextBlock: res.nextBlock,
|
|
173
|
+
responseBlocks: res.responseBlocks,
|
|
168
174
|
archiveHeight: res.archiveHeight->Option.getOr(0), //Archive Height is only None if height is 0
|
|
169
175
|
transactionStore,
|
|
170
176
|
blockStore,
|
|
@@ -137,13 +137,15 @@ function extractMissingParams(exn) {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
async function query(client, fromBlock, toBlock, maxNumLogs, registrationIndexes, addressSet, clientFilteredContracts) {
|
|
140
|
+
async function query(client, fromBlock, toBlock, maxNumLogs, registrationIndexes, addressSet, clientFilteredContracts, includeAllBlocks) {
|
|
141
|
+
let query_includeAllBlocks = includeAllBlocks ? true : undefined;
|
|
141
142
|
let query$1 = {
|
|
142
143
|
fromBlock: fromBlock,
|
|
143
144
|
toBlock: toBlock,
|
|
144
145
|
maxNumLogs: maxNumLogs,
|
|
145
146
|
registrationIndexes: registrationIndexes,
|
|
146
|
-
clientFilteredContracts: clientFilteredContracts
|
|
147
|
+
clientFilteredContracts: clientFilteredContracts,
|
|
148
|
+
includeAllBlocks: query_includeAllBlocks
|
|
147
149
|
};
|
|
148
150
|
let match;
|
|
149
151
|
try {
|
|
@@ -176,6 +178,7 @@ async function query(client, fromBlock, toBlock, maxNumLogs, registrationIndexes
|
|
|
176
178
|
items: res.items,
|
|
177
179
|
nextBlock: res.nextBlock,
|
|
178
180
|
archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
|
|
181
|
+
responseBlocks: res.responseBlocks,
|
|
179
182
|
transactionStore: match[1],
|
|
180
183
|
blockStore: match[2]
|
|
181
184
|
};
|
|
@@ -2,6 +2,7 @@ type logsQueryPage = {
|
|
|
2
2
|
items: array<HyperSyncClient.EventItems.item>,
|
|
3
3
|
nextBlock: int,
|
|
4
4
|
archiveHeight: int,
|
|
5
|
+
responseBlocks: int,
|
|
5
6
|
transactionStore: TransactionStore.t,
|
|
6
7
|
blockStore: BlockStore.t,
|
|
7
8
|
}
|
|
@@ -56,5 +57,6 @@ module GetLogs: {
|
|
|
56
57
|
~registrationIndexes: array<int>,
|
|
57
58
|
~addressSet: AddressSet.t,
|
|
58
59
|
~clientFilteredContracts: option<array<string>>,
|
|
60
|
+
~includeAllBlocks: bool,
|
|
59
61
|
) => promise<logsQueryPage>
|
|
60
62
|
}
|
|
@@ -262,6 +262,9 @@ module EventItems = {
|
|
|
262
262
|
// depend on addresses (client-side filtering). None/empty means
|
|
263
263
|
// every address-dependent contract is filtered server-side.
|
|
264
264
|
clientFilteredContracts: option<array<string>>,
|
|
265
|
+
// Return a header for every block in the range, not only the ones a log
|
|
266
|
+
// landed on. Absent means only the blocks logs came from.
|
|
267
|
+
includeAllBlocks?: bool,
|
|
265
268
|
}
|
|
266
269
|
|
|
267
270
|
type item = {
|
|
@@ -283,6 +286,9 @@ module EventItems = {
|
|
|
283
286
|
archiveHeight: option<int>,
|
|
284
287
|
nextBlock: int,
|
|
285
288
|
items: array<item>,
|
|
289
|
+
// Blocks the server returned for the query, counted before routing drops
|
|
290
|
+
// the ones no item joins to.
|
|
291
|
+
responseBlocks: int,
|
|
286
292
|
}
|
|
287
293
|
}
|
|
288
294
|
|
|
@@ -25,7 +25,7 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~onHeight, ~onStatus) =>
|
|
|
25
25
|
args.headers
|
|
26
26
|
->Option.getOr(Dict.make())
|
|
27
27
|
->Utils.Dict.merge(
|
|
28
|
-
|
|
28
|
+
dict{"Authorization": `Bearer ${apiToken}`, "User-Agent": userAgent},
|
|
29
29
|
)
|
|
30
30
|
EventSource.Fetch.fetch(url, ~args={...args, headers: headers})
|
|
31
31
|
},
|
|
@@ -35,16 +35,10 @@ function subscribe(hyperSyncUrl, apiToken, onHeight, onStatus) {
|
|
|
35
35
|
let userAgent = `hyperindex/` + Utils.EnvioPackage.value.version;
|
|
36
36
|
let es = new Eventsource.EventSource(hyperSyncUrl + `/height/sse`, {
|
|
37
37
|
fetch: (url, args) => {
|
|
38
|
-
let headers = Utils.Dict.merge(Stdlib_Option.getOr(args.headers, {}),
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
],
|
|
43
|
-
[
|
|
44
|
-
"User-Agent",
|
|
45
|
-
userAgent
|
|
46
|
-
]
|
|
47
|
-
]));
|
|
38
|
+
let headers = Utils.Dict.merge(Stdlib_Option.getOr(args.headers, {}), {
|
|
39
|
+
Authorization: `Bearer ` + apiToken,
|
|
40
|
+
"User-Agent": userAgent
|
|
41
|
+
});
|
|
48
42
|
let newrecord = {...args};
|
|
49
43
|
return fetch(url, (newrecord.headers = headers, newrecord));
|
|
50
44
|
}
|
|
@@ -2,4 +2,11 @@
|
|
|
2
2
|
// in its own leaf module (rather than on `Source`) so the client FFI bindings
|
|
3
3
|
// can name it without importing `Source` — which would form a dependency cycle
|
|
4
4
|
// through `Env → HyperSyncClient → Source → FetchState → Env`.
|
|
5
|
-
type t = {
|
|
5
|
+
type t = {
|
|
6
|
+
method: string,
|
|
7
|
+
seconds: float,
|
|
8
|
+
// Blocks the backend returned for this request, before any client-side
|
|
9
|
+
// routing drops them. Absent for methods whose responses aren't measured in
|
|
10
|
+
// blocks, so a zero always means the request came back empty.
|
|
11
|
+
responseBlocks?: int,
|
|
12
|
+
}
|
|
@@ -874,7 +874,7 @@ function make(param) {
|
|
|
874
874
|
Error: new Error()
|
|
875
875
|
};
|
|
876
876
|
}, lowercaseAddresses);
|
|
877
|
-
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, knownHeight, partitionId, selection, param, retry, param$
|
|
877
|
+
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, param, knownHeight, partitionId, selection, param$1, retry, param$2) => {
|
|
878
878
|
let startFetchingBatchTimeRef = Performance.now();
|
|
879
879
|
let toBlock$1 = toBlock !== undefined ? Primitive_int.min(toBlock, knownHeight) : knownHeight;
|
|
880
880
|
let firstBlockPromise = fromBlock > 0 && fromBlock <= toBlock$1 ? LazyLoader.get(blockLoader.contents, fromBlock).then(json => parseBlockInfo(json)) : Promise.resolve(undefined);
|
|
@@ -27,7 +27,7 @@ function make(items, endBlock, chainId, addressStore, ecosystemOpt, transactionS
|
|
|
27
27
|
height: reportedHeight,
|
|
28
28
|
requestStats: []
|
|
29
29
|
}),
|
|
30
|
-
getItemsOrThrow: (fromBlock, toBlock, addressSet, param, param$1, selection, param$
|
|
30
|
+
getItemsOrThrow: (fromBlock, toBlock, addressSet, param, param$1, param$2, selection, param$3, param$4, param$5) => {
|
|
31
31
|
let toBlockQueried = toBlock !== undefined ? toBlock : reportedHeight;
|
|
32
32
|
let selectionRegistrationIndexes = new Set();
|
|
33
33
|
selection.onEventRegistrations.forEach(reg => {
|
package/src/sources/Source.res
CHANGED
|
@@ -8,9 +8,10 @@ type blockRangeFetchStats = {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
// A single backend request a source method actually made (cache/dedup hits
|
|
11
|
-
// aren't requests), with the time it took
|
|
12
|
-
// per (source, method) into the
|
|
13
|
-
|
|
11
|
+
// aren't requests), with the time it took and how much it brought back.
|
|
12
|
+
// SourceManager aggregates these per (source, method) into the
|
|
13
|
+
// envio_source_request_* and envio_source_response_* metrics.
|
|
14
|
+
type requestStat = RequestStat.t = {method: string, seconds: float, responseBlocks?: int}
|
|
14
15
|
|
|
15
16
|
// Native clients wrap a failure of a multi-request operation in a structured
|
|
16
17
|
// payload, so the source can still return timings when SourceManager retries
|
|
@@ -196,6 +197,13 @@ type t = {
|
|
|
196
197
|
// straight to its Rust client, which builds the query's address filter from
|
|
197
198
|
// it and gates every returned item against the chain-wide store.
|
|
198
199
|
~addressSet: AddressSet.t,
|
|
200
|
+
// Return a header for every block in the range, not only the ones an item
|
|
201
|
+
// landed on. The progress block's timestamp is what measures how far behind
|
|
202
|
+
// chain time the indexer is, and at the head that block often carries no
|
|
203
|
+
// item of its own. Only set once the chain is at the head, where the range
|
|
204
|
+
// is a handful of blocks; over a backfill range it would be a header per
|
|
205
|
+
// block for no gain.
|
|
206
|
+
~includeAllBlocks: bool,
|
|
199
207
|
~knownHeight: int,
|
|
200
208
|
~partitionId: string,
|
|
201
209
|
~selection: FetchState.selection,
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
type sourceManagerStatus = Idle | WaitingForNewBlock | Querying
|
|
2
2
|
|
|
3
|
-
// Cumulative per-method request
|
|
4
|
-
// requestStat arrays returned by its methods. Rendered into
|
|
5
|
-
// envio_source_request_*
|
|
6
|
-
type requestStatAgg = {
|
|
3
|
+
// Cumulative per-method request stats for a source, aggregated from the
|
|
4
|
+
// requestStat arrays returned by its methods. Rendered into the
|
|
5
|
+
// envio_source_request_* and envio_source_response_* metrics.
|
|
6
|
+
type requestStatAgg = {
|
|
7
|
+
mutable count: int,
|
|
8
|
+
mutable seconds: float,
|
|
9
|
+
mutable responseBlocks: option<int>,
|
|
10
|
+
mutable emptyResponseCount: int,
|
|
11
|
+
}
|
|
7
12
|
|
|
8
13
|
type sourceState = {
|
|
9
14
|
source: Source.t,
|
|
@@ -19,12 +24,23 @@ let recordStatsInto = (
|
|
|
19
24
|
aggregates: dict<requestStatAgg>,
|
|
20
25
|
requestStats: array<Source.requestStat>,
|
|
21
26
|
) => {
|
|
22
|
-
requestStats->Array.forEach(({method, seconds}) => {
|
|
23
|
-
switch aggregates->Utils.Dict.dangerouslyGetNonOption(method) {
|
|
24
|
-
| Some(agg) =>
|
|
25
|
-
|
|
26
|
-
agg
|
|
27
|
-
|
|
27
|
+
requestStats->Array.forEach(({method, seconds, responseBlocks: ?responseBlocks}) => {
|
|
28
|
+
let agg = switch aggregates->Utils.Dict.dangerouslyGetNonOption(method) {
|
|
29
|
+
| Some(agg) => agg
|
|
30
|
+
| None =>
|
|
31
|
+
let agg = {count: 0, seconds: 0., responseBlocks: None, emptyResponseCount: 0}
|
|
32
|
+
aggregates->Dict.set(method, agg)
|
|
33
|
+
agg
|
|
34
|
+
}
|
|
35
|
+
agg.count = agg.count + 1
|
|
36
|
+
agg.seconds = agg.seconds +. seconds
|
|
37
|
+
switch responseBlocks {
|
|
38
|
+
| Some(responseBlocks) =>
|
|
39
|
+
agg.responseBlocks = Some(agg.responseBlocks->Option.getOr(0) + responseBlocks)
|
|
40
|
+
if responseBlocks === 0 {
|
|
41
|
+
agg.emptyResponseCount = agg.emptyResponseCount + 1
|
|
42
|
+
}
|
|
43
|
+
| None => ()
|
|
28
44
|
}
|
|
29
45
|
})
|
|
30
46
|
}
|
|
@@ -40,6 +56,8 @@ type requestStatSample = {
|
|
|
40
56
|
method: string,
|
|
41
57
|
count: int,
|
|
42
58
|
seconds: float,
|
|
59
|
+
responseBlocks: option<int>,
|
|
60
|
+
emptyResponseCount: int,
|
|
43
61
|
}
|
|
44
62
|
|
|
45
63
|
// Encapsulates the fetching logic for a chain's sources.
|
|
@@ -93,6 +111,8 @@ let getRequestStatSamples = (sourceManager: t): array<requestStatSample> => {
|
|
|
93
111
|
method,
|
|
94
112
|
count: agg.count,
|
|
95
113
|
seconds: agg.seconds,
|
|
114
|
+
responseBlocks: agg.responseBlocks,
|
|
115
|
+
emptyResponseCount: agg.emptyResponseCount,
|
|
96
116
|
})
|
|
97
117
|
->ignore
|
|
98
118
|
})
|
|
@@ -685,7 +705,7 @@ let waitForNewBlock = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedPoll
|
|
|
685
705
|
logger->Logging.childTrace(
|
|
686
706
|
reducedPolling
|
|
687
707
|
? `Waiting for new blocks with reduced polling (${(sourceManager.reducedPollingInterval / 1000)
|
|
688
|
-
->Int.toString}s)
|
|
708
|
+
->Int.toString}s) until the indexer enters realtime mode.`
|
|
689
709
|
: "Initiating check for new blocks.",
|
|
690
710
|
)
|
|
691
711
|
sourceManager.waitingLogged = true
|
|
@@ -697,8 +717,8 @@ let waitForNewBlock = (sourceManager: t, ~knownHeight, ~isRealtime, ~reducedPoll
|
|
|
697
717
|
// cadence the sources poll at and the level the closing line is logged at.
|
|
698
718
|
let stalled = ref(false)
|
|
699
719
|
|
|
700
|
-
// Use a much longer stall timeout when reduced polling is active
|
|
701
|
-
//
|
|
720
|
+
// Use a much longer stall timeout when reduced polling is active, so a chain
|
|
721
|
+
// deliberately asking rarely doesn't report itself stalled between polls.
|
|
702
722
|
let stallTimeout = if reducedPolling {
|
|
703
723
|
sourceManager.reducedPollingInterval * 2
|
|
704
724
|
} else if isRealtime {
|
|
@@ -928,6 +948,7 @@ let executeQuery = async (
|
|
|
928
948
|
~fromBlock=query.fromBlock,
|
|
929
949
|
~toBlock,
|
|
930
950
|
~addressSet=query.addresses,
|
|
951
|
+
~includeAllBlocks=isRealtime,
|
|
931
952
|
~partitionId=query.partitionId,
|
|
932
953
|
~knownHeight,
|
|
933
954
|
~selection=query.selection->FetchState.narrowSelectionToRange(~toBlock),
|
|
@@ -16,17 +16,32 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
|
|
|
16
16
|
|
|
17
17
|
function recordStatsInto(aggregates, requestStats) {
|
|
18
18
|
requestStats.forEach(param => {
|
|
19
|
-
let
|
|
19
|
+
let responseBlocks = param.responseBlocks;
|
|
20
20
|
let method = param.method;
|
|
21
21
|
let agg = aggregates[method];
|
|
22
|
+
let agg$1;
|
|
22
23
|
if (agg !== undefined) {
|
|
23
|
-
agg
|
|
24
|
-
agg.seconds = agg.seconds + seconds;
|
|
24
|
+
agg$1 = agg;
|
|
25
25
|
} else {
|
|
26
|
-
|
|
27
|
-
count:
|
|
28
|
-
seconds:
|
|
26
|
+
let agg$2 = {
|
|
27
|
+
count: 0,
|
|
28
|
+
seconds: 0,
|
|
29
|
+
responseBlocks: undefined,
|
|
30
|
+
emptyResponseCount: 0
|
|
29
31
|
};
|
|
32
|
+
aggregates[method] = agg$2;
|
|
33
|
+
agg$1 = agg$2;
|
|
34
|
+
}
|
|
35
|
+
agg$1.count = agg$1.count + 1 | 0;
|
|
36
|
+
agg$1.seconds = agg$1.seconds + param.seconds;
|
|
37
|
+
if (responseBlocks !== undefined) {
|
|
38
|
+
agg$1.responseBlocks = Stdlib_Option.getOr(agg$1.responseBlocks, 0) + responseBlocks | 0;
|
|
39
|
+
if (responseBlocks === 0) {
|
|
40
|
+
agg$1.emptyResponseCount = agg$1.emptyResponseCount + 1 | 0;
|
|
41
|
+
return;
|
|
42
|
+
} else {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
30
45
|
}
|
|
31
46
|
});
|
|
32
47
|
}
|
|
@@ -45,7 +60,9 @@ function getRequestStatSamples(sourceManager) {
|
|
|
45
60
|
chainId: chainId,
|
|
46
61
|
method: method,
|
|
47
62
|
count: agg.count,
|
|
48
|
-
seconds: agg.seconds
|
|
63
|
+
seconds: agg.seconds,
|
|
64
|
+
responseBlocks: agg.responseBlocks,
|
|
65
|
+
emptyResponseCount: agg.emptyResponseCount
|
|
49
66
|
});
|
|
50
67
|
});
|
|
51
68
|
});
|
|
@@ -520,7 +537,7 @@ function waitForNewBlock(sourceManager, knownHeight, isRealtime, reducedPolling)
|
|
|
520
537
|
knownHeight: knownHeight
|
|
521
538
|
});
|
|
522
539
|
if (!sourceManager.waitingLogged) {
|
|
523
|
-
Logging.childTrace(logger, reducedPolling ? `Waiting for new blocks with reduced polling (` + (sourceManager.reducedPollingInterval / 1000 | 0).toString() + `s)
|
|
540
|
+
Logging.childTrace(logger, reducedPolling ? `Waiting for new blocks with reduced polling (` + (sourceManager.reducedPollingInterval / 1000 | 0).toString() + `s) until the indexer enters realtime mode.` : "Initiating check for new blocks.");
|
|
524
541
|
sourceManager.waitingLogged = true;
|
|
525
542
|
}
|
|
526
543
|
let mainSources = getNextSources(sourceManager, isRealtime, undefined);
|
|
@@ -674,7 +691,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
|
|
|
674
691
|
retry: retry
|
|
675
692
|
});
|
|
676
693
|
try {
|
|
677
|
-
let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addresses, knownHeight, query.partitionId, FetchState.narrowSelectionToRange(query.selection, toBlock), query.itemsTarget, retry, logger$2);
|
|
694
|
+
let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addresses, isRealtime, knownHeight, query.partitionId, FetchState.narrowSelectionToRange(query.selection, toBlock), query.itemsTarget, retry, logger$2);
|
|
678
695
|
recordStatsInto(sourceState.requestStats, response.requestStats);
|
|
679
696
|
validateResponseBlockStore("getItems", response.blockStore, undefined);
|
|
680
697
|
sourceState.lastFailedAt = undefined;
|
|
@@ -143,6 +143,11 @@ module EventItems = {
|
|
|
143
143
|
// depend on addresses (client-side filtering). None/empty means every
|
|
144
144
|
// address-dependent program is filtered server-side.
|
|
145
145
|
clientFilteredContracts: option<array<string>>,
|
|
146
|
+
// Return a block for every slot in the range, not only the ones an
|
|
147
|
+
// instruction landed on. Absent means only the slots instructions came
|
|
148
|
+
// from, which leaves a skipped slot indistinguishable from an unfetched
|
|
149
|
+
// one.
|
|
150
|
+
includeAllBlocks?: bool,
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
// NAPI encodes Rust `None` as `null`, never `undefined`, so an unselected
|
|
@@ -147,6 +147,7 @@ let make = (
|
|
|
147
147
|
~fromBlock,
|
|
148
148
|
~toBlock,
|
|
149
149
|
~addressSet,
|
|
150
|
+
~includeAllBlocks,
|
|
150
151
|
~knownHeight,
|
|
151
152
|
~partitionId as _,
|
|
152
153
|
~selection: FetchState.selection,
|
|
@@ -163,6 +164,8 @@ let make = (
|
|
|
163
164
|
maxNumInstructions: ?itemsTarget,
|
|
164
165
|
registrationIndexes: selection.onEventRegistrations->Array.map(reg => reg.index),
|
|
165
166
|
clientFilteredContracts: selection.clientFilteredContracts,
|
|
167
|
+
// Absent rather than false, so a backfill query is the one it always was.
|
|
168
|
+
includeAllBlocks: ?(includeAllBlocks ? Some(true) : None),
|
|
166
169
|
}
|
|
167
170
|
|
|
168
171
|
let (resp, transactionStore, blockStore) = try await client.getEventItems(
|
|
@@ -106,17 +106,19 @@ function make(param) {
|
|
|
106
106
|
let chainId = param.chainId;
|
|
107
107
|
let apiToken = HyperSync.requireApiToken(param.apiToken);
|
|
108
108
|
let client = SvmHyperSyncClient.make(endpointUrl, apiToken, param.clientTimeoutMillis, undefined, undefined, SvmHyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations), param.addressStore);
|
|
109
|
-
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, knownHeight, param, selection, itemsTarget, retry, param$1) => {
|
|
109
|
+
let getItemsOrThrow = async (fromBlock, toBlock, addressSet, includeAllBlocks, knownHeight, param, selection, itemsTarget, retry, param$1) => {
|
|
110
110
|
let totalTimeRef = Performance.now();
|
|
111
111
|
let pageFetchRef = Performance.now();
|
|
112
112
|
let query_registrationIndexes = selection.onEventRegistrations.map(reg => reg.index);
|
|
113
113
|
let query_clientFilteredContracts = selection.clientFilteredContracts;
|
|
114
|
+
let query_includeAllBlocks = includeAllBlocks ? true : undefined;
|
|
114
115
|
let query = {
|
|
115
116
|
fromSlot: fromBlock,
|
|
116
117
|
toSlot: toBlock,
|
|
117
118
|
maxNumInstructions: itemsTarget,
|
|
118
119
|
registrationIndexes: query_registrationIndexes,
|
|
119
|
-
clientFilteredContracts: query_clientFilteredContracts
|
|
120
|
+
clientFilteredContracts: query_clientFilteredContracts,
|
|
121
|
+
includeAllBlocks: query_includeAllBlocks
|
|
120
122
|
};
|
|
121
123
|
let match;
|
|
122
124
|
try {
|