envio 3.1.2 → 3.2.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 +83 -11
- package/fuel.schema.json +83 -11
- package/index.d.ts +184 -3
- package/package.json +6 -6
- package/src/Batch.res +2 -2
- package/src/ChainFetcher.res +27 -3
- package/src/ChainFetcher.res.mjs +17 -3
- package/src/ChainManager.res +163 -0
- package/src/ChainManager.res.mjs +136 -0
- package/src/Config.res +213 -30
- package/src/Config.res.mjs +102 -41
- package/src/Core.res +16 -10
- package/src/Ecosystem.res +0 -3
- package/src/Env.res +2 -2
- package/src/Env.res.mjs +2 -2
- package/src/Envio.res +101 -2
- package/src/Envio.res.mjs +2 -3
- package/src/EventConfigBuilder.res +87 -0
- package/src/EventConfigBuilder.res.mjs +53 -0
- package/src/EventUtils.res +2 -2
- package/src/FetchState.res +63 -67
- package/src/FetchState.res.mjs +44 -42
- package/src/GlobalState.res +219 -363
- package/src/GlobalState.res.mjs +314 -491
- package/src/GlobalStateManager.res +49 -59
- package/src/GlobalStateManager.res.mjs +5 -4
- package/src/GlobalStateManager.resi +1 -1
- package/src/HandlerLoader.res +18 -2
- package/src/HandlerLoader.res.mjs +16 -34
- package/src/HandlerRegister.res +9 -9
- package/src/HandlerRegister.res.mjs +9 -9
- package/src/Hasura.res +102 -32
- package/src/Hasura.res.mjs +88 -34
- package/src/InMemoryStore.res +10 -1
- package/src/InMemoryStore.res.mjs +4 -1
- package/src/InMemoryTable.res +83 -136
- package/src/InMemoryTable.res.mjs +57 -86
- package/src/Internal.res +70 -5
- package/src/Internal.res.mjs +2 -8
- package/src/LazyLoader.res +2 -2
- package/src/LazyLoader.res.mjs +3 -3
- package/src/LoadLayer.res +47 -60
- package/src/LoadLayer.res.mjs +28 -50
- package/src/LoadLayer.resi +2 -5
- package/src/LogSelection.res +90 -21
- package/src/LogSelection.res.mjs +72 -21
- package/src/Logging.res +1 -1
- package/src/Main.res +61 -2
- package/src/Main.res.mjs +37 -1
- package/src/Persistence.res +3 -16
- package/src/PgStorage.res +125 -114
- package/src/PgStorage.res.mjs +112 -95
- package/src/Ports.res +5 -0
- package/src/Ports.res.mjs +9 -0
- package/src/Prometheus.res +3 -3
- package/src/Prometheus.res.mjs +4 -4
- package/src/ReorgDetection.res +4 -4
- package/src/ReorgDetection.res.mjs +4 -5
- package/src/SafeCheckpointTracking.res +16 -16
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/SimulateItems.res +10 -14
- package/src/SimulateItems.res.mjs +5 -2
- package/src/Sink.res +1 -1
- package/src/Sink.res.mjs +1 -2
- package/src/SvmTypes.res +9 -0
- package/src/SvmTypes.res.mjs +14 -0
- package/src/TestIndexer.res +35 -68
- package/src/TestIndexer.res.mjs +17 -48
- package/src/TestIndexerProxyStorage.res +23 -23
- package/src/TestIndexerProxyStorage.res.mjs +12 -15
- package/src/Throttler.res +2 -2
- package/src/Time.res +2 -2
- package/src/Time.res.mjs +2 -2
- package/src/UserContext.res +19 -118
- package/src/UserContext.res.mjs +10 -66
- package/src/Utils.res +15 -15
- package/src/Utils.res.mjs +7 -8
- package/src/adapters/MarkBatchProcessedAdapter.res +5 -0
- package/src/adapters/MarkBatchProcessedAdapter.res.mjs +14 -0
- package/src/bindings/BigDecimal.res +1 -1
- package/src/bindings/BigDecimal.res.mjs +2 -2
- package/src/bindings/ClickHouse.res +8 -6
- package/src/bindings/ClickHouse.res.mjs +5 -5
- package/src/bindings/Hrtime.res +1 -1
- package/src/bindings/Pino.res +2 -2
- package/src/bindings/Pino.res.mjs +3 -4
- package/src/db/EntityFilter.res +410 -0
- package/src/db/EntityFilter.res.mjs +424 -0
- package/src/db/EntityHistory.res +1 -1
- package/src/db/EntityHistory.res.mjs +1 -1
- package/src/db/InternalTable.res +10 -10
- package/src/db/InternalTable.res.mjs +41 -45
- package/src/db/Schema.res +2 -2
- package/src/db/Schema.res.mjs +3 -3
- package/src/db/Table.res +106 -22
- package/src/db/Table.res.mjs +84 -35
- package/src/sources/EventRouter.res +67 -2
- package/src/sources/EventRouter.res.mjs +45 -3
- package/src/sources/Evm.res +0 -7
- package/src/sources/Evm.res.mjs +0 -15
- package/src/sources/EvmChain.res +1 -1
- package/src/sources/EvmChain.res.mjs +1 -2
- package/src/sources/EvmRpcClient.res +42 -0
- package/src/sources/EvmRpcClient.res.mjs +64 -0
- package/src/sources/Fuel.res +0 -7
- package/src/sources/Fuel.res.mjs +0 -15
- package/src/sources/HyperFuelSource.res +5 -4
- package/src/sources/HyperFuelSource.res.mjs +2 -2
- package/src/sources/HyperSyncClient.res +9 -5
- package/src/sources/HyperSyncClient.res.mjs +2 -2
- package/src/sources/HyperSyncHeightStream.res +2 -2
- package/src/sources/HyperSyncHeightStream.res.mjs +2 -2
- package/src/sources/HyperSyncSource.res +12 -11
- package/src/sources/HyperSyncSource.res.mjs +6 -6
- package/src/sources/Rpc.res +1 -5
- package/src/sources/Rpc.res.mjs +1 -9
- package/src/sources/RpcSource.res +57 -21
- package/src/sources/RpcSource.res.mjs +47 -20
- package/src/sources/RpcWebSocketHeightStream.res +1 -1
- package/src/sources/SourceManager.res +3 -2
- package/src/sources/SourceManager.res.mjs +1 -1
- package/src/sources/Svm.res +3 -10
- package/src/sources/Svm.res.mjs +4 -18
- package/src/sources/SvmHyperSyncClient.res +265 -0
- package/src/sources/SvmHyperSyncClient.res.mjs +28 -0
- package/src/sources/SvmHyperSyncSource.res +638 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +557 -0
- package/src/tui/Tui.res +9 -2
- package/src/tui/Tui.res.mjs +18 -3
- package/src/tui/components/BufferedProgressBar.res +2 -2
- package/src/tui/components/TuiData.res +3 -0
- package/svm.schema.json +523 -14
- package/src/TableIndices.res +0 -115
- package/src/TableIndices.res.mjs +0 -144
|
@@ -309,6 +309,39 @@ let resolveFieldSelection = (
|
|
|
309
309
|
(selectedBlockFields, selectedTransactionFields)
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
// ============== Client-side address filter ==============
|
|
313
|
+
|
|
314
|
+
let compileAddressFilter: string => (
|
|
315
|
+
Internal.event,
|
|
316
|
+
int,
|
|
317
|
+
dict<Internal.indexingContract>,
|
|
318
|
+
) => bool = %raw(`function (body) {
|
|
319
|
+
return new Function("event", "blockNumber", "indexingAddresses", body);
|
|
320
|
+
}`)
|
|
321
|
+
|
|
322
|
+
// Body of the client-side address filter for a DNF of address-filtered param
|
|
323
|
+
// names (OR of AND-groups): keep the event only if some group's params are all
|
|
324
|
+
// registered at or before the log's block. The DNF is fixed here, so it's
|
|
325
|
+
// unrolled into one boolean expression — no per-event closure, loop, or array.
|
|
326
|
+
// `None` when there's no address-param filter. Exposed for snapshotting.
|
|
327
|
+
let buildAddressFilterBody = (groups: array<array<string>>): option<string> => {
|
|
328
|
+
switch groups {
|
|
329
|
+
| [] => None
|
|
330
|
+
| _ =>
|
|
331
|
+
let leaf = name =>
|
|
332
|
+
`(ic = indexingAddresses[p[${JSON.stringify(
|
|
333
|
+
JSON.String(name),
|
|
334
|
+
)}]]) !== undefined && ic.effectiveStartBlock <= blockNumber`
|
|
335
|
+
let groupExprs =
|
|
336
|
+
groups->Array.map(group => "(" ++ group->Array.map(leaf)->Array.join(" && ") ++ ")")
|
|
337
|
+
Some("var p = event.params, ic; return " ++ groupExprs->Array.join(" || ") ++ ";")
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let buildAddressFilter = (groups: array<array<string>>): option<
|
|
342
|
+
(Internal.event, int, dict<Internal.indexingContract>) => bool,
|
|
343
|
+
> => buildAddressFilterBody(groups)->Option.map(compileAddressFilter)
|
|
344
|
+
|
|
312
345
|
// ============== Build complete EVM event config ==============
|
|
313
346
|
|
|
314
347
|
let buildEvmEventConfig = (
|
|
@@ -334,6 +367,7 @@ let buildEvmEventConfig = (
|
|
|
334
367
|
let {
|
|
335
368
|
getEventFiltersOrThrow,
|
|
336
369
|
filterByAddresses,
|
|
370
|
+
addressFilterParamGroups,
|
|
337
371
|
startBlock: whereStartBlock,
|
|
338
372
|
} = LogSelection.parseEventFiltersOrThrow(
|
|
339
373
|
~eventFilters,
|
|
@@ -374,6 +408,7 @@ let buildEvmEventConfig = (
|
|
|
374
408
|
simulateParamsSchema: buildSimulateParamsSchema(params),
|
|
375
409
|
getEventFiltersOrThrow,
|
|
376
410
|
filterByAddresses,
|
|
411
|
+
clientAddressFilter: ?buildAddressFilter(addressFilterParamGroups),
|
|
377
412
|
dependsOnAddresses: !isWildcard || filterByAddresses,
|
|
378
413
|
startBlock: resolvedStartBlock,
|
|
379
414
|
selectedBlockFields,
|
|
@@ -386,6 +421,58 @@ let buildEvmEventConfig = (
|
|
|
386
421
|
|
|
387
422
|
// ============== Build Fuel event config ==============
|
|
388
423
|
|
|
424
|
+
let buildSvmInstructionEventConfig = (
|
|
425
|
+
~contractName: string,
|
|
426
|
+
~instructionName: string,
|
|
427
|
+
~programId: SvmTypes.Pubkey.t,
|
|
428
|
+
~discriminator: option<string>,
|
|
429
|
+
~discriminatorByteLen: int,
|
|
430
|
+
~includeTransaction: bool,
|
|
431
|
+
~includeLogs: bool,
|
|
432
|
+
~includeTokenBalances: bool,
|
|
433
|
+
~accountFilters: array<Internal.svmAccountFilterGroup>,
|
|
434
|
+
~isInner: option<bool>,
|
|
435
|
+
~isWildcard: bool,
|
|
436
|
+
~handler: option<Internal.handler>,
|
|
437
|
+
~contractRegister: option<Internal.contractRegister>,
|
|
438
|
+
~accounts: array<string>=[],
|
|
439
|
+
~args: JSON.t=JSON.Null,
|
|
440
|
+
~definedTypes: JSON.t=JSON.Null,
|
|
441
|
+
~startBlock: option<int>=?,
|
|
442
|
+
): Internal.svmInstructionEventConfig => {
|
|
443
|
+
let paramsSchema =
|
|
444
|
+
S.json(~validate=false)
|
|
445
|
+
->Utils.Schema.coerceToJsonPgType
|
|
446
|
+
->(Utils.magic: S.t<JSON.t> => S.t<Internal.eventParams>)
|
|
447
|
+
{
|
|
448
|
+
id: switch discriminator {
|
|
449
|
+
| Some(d) => d
|
|
450
|
+
| None => "none"
|
|
451
|
+
},
|
|
452
|
+
name: instructionName,
|
|
453
|
+
contractName,
|
|
454
|
+
isWildcard,
|
|
455
|
+
handler,
|
|
456
|
+
contractRegister,
|
|
457
|
+
paramsRawEventSchema: paramsSchema,
|
|
458
|
+
simulateParamsSchema: paramsSchema,
|
|
459
|
+
filterByAddresses: false,
|
|
460
|
+
dependsOnAddresses: !isWildcard,
|
|
461
|
+
startBlock,
|
|
462
|
+
programId,
|
|
463
|
+
discriminator,
|
|
464
|
+
discriminatorByteLen,
|
|
465
|
+
includeTransaction,
|
|
466
|
+
includeLogs,
|
|
467
|
+
includeTokenBalances,
|
|
468
|
+
accountFilters,
|
|
469
|
+
isInner,
|
|
470
|
+
accounts,
|
|
471
|
+
args,
|
|
472
|
+
definedTypes,
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
389
476
|
let buildFuelEventConfig = (
|
|
390
477
|
~contractName: string,
|
|
391
478
|
~eventName: string,
|
|
@@ -251,6 +251,23 @@ function resolveFieldSelection(blockFields, transactionFields, globalBlockFields
|
|
|
251
251
|
];
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
let compileAddressFilter = (function (body) {
|
|
255
|
+
return new Function("event", "blockNumber", "indexingAddresses", body);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
function buildAddressFilterBody(groups) {
|
|
259
|
+
if (groups.length === 0) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
let leaf = name => `(ic = indexingAddresses[p[` + JSON.stringify(name) + `]]) !== undefined && ic.effectiveStartBlock <= blockNumber`;
|
|
263
|
+
let groupExprs = groups.map(group => "(" + group.map(leaf).join(" && ") + ")");
|
|
264
|
+
return "var p = event.params, ic; return " + groupExprs.join(" || ") + ";";
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function buildAddressFilter(groups) {
|
|
268
|
+
return Stdlib_Option.map(buildAddressFilterBody(groups), compileAddressFilter);
|
|
269
|
+
}
|
|
270
|
+
|
|
254
271
|
function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcard, handler, contractRegister, eventFilters, probeChainId, onEventBlockFilterSchema, blockFields, transactionFields, startBlock, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
|
|
255
272
|
let globalBlockFieldsSet = globalBlockFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalBlockFieldsSetOpt) : new Set();
|
|
256
273
|
let globalTransactionFieldsSet = globalTransactionFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalTransactionFieldsSetOpt) : new Set();
|
|
@@ -274,6 +291,7 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
|
|
|
274
291
|
isWildcard: isWildcard,
|
|
275
292
|
filterByAddresses: filterByAddresses,
|
|
276
293
|
dependsOnAddresses: !isWildcard || filterByAddresses,
|
|
294
|
+
clientAddressFilter: Stdlib_Option.map(buildAddressFilterBody(match.addressFilterParamGroups), compileAddressFilter),
|
|
277
295
|
handler: handler,
|
|
278
296
|
contractRegister: contractRegister,
|
|
279
297
|
paramsRawEventSchema: buildParamsSchema(params),
|
|
@@ -288,6 +306,37 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
|
|
|
288
306
|
};
|
|
289
307
|
}
|
|
290
308
|
|
|
309
|
+
function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeTransaction, includeLogs, includeTokenBalances, accountFilters, isInner, isWildcard, handler, contractRegister, accountsOpt, argsOpt, definedTypesOpt, startBlock) {
|
|
310
|
+
let accounts = accountsOpt !== undefined ? accountsOpt : [];
|
|
311
|
+
let args = argsOpt !== undefined ? argsOpt : null;
|
|
312
|
+
let definedTypes = definedTypesOpt !== undefined ? definedTypesOpt : null;
|
|
313
|
+
let paramsSchema = Utils.Schema.coerceToJsonPgType(S$RescriptSchema.json(false));
|
|
314
|
+
return {
|
|
315
|
+
id: discriminator !== undefined ? discriminator : "none",
|
|
316
|
+
name: instructionName,
|
|
317
|
+
contractName: contractName,
|
|
318
|
+
isWildcard: isWildcard,
|
|
319
|
+
filterByAddresses: false,
|
|
320
|
+
dependsOnAddresses: !isWildcard,
|
|
321
|
+
handler: handler,
|
|
322
|
+
contractRegister: contractRegister,
|
|
323
|
+
paramsRawEventSchema: paramsSchema,
|
|
324
|
+
simulateParamsSchema: paramsSchema,
|
|
325
|
+
startBlock: startBlock,
|
|
326
|
+
programId: programId,
|
|
327
|
+
discriminator: discriminator,
|
|
328
|
+
discriminatorByteLen: discriminatorByteLen,
|
|
329
|
+
includeTransaction: includeTransaction,
|
|
330
|
+
includeLogs: includeLogs,
|
|
331
|
+
includeTokenBalances: includeTokenBalances,
|
|
332
|
+
accountFilters: accountFilters,
|
|
333
|
+
isInner: isInner,
|
|
334
|
+
accounts: accounts,
|
|
335
|
+
args: args,
|
|
336
|
+
definedTypes: definedTypes
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
291
340
|
function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, isWildcard, handler, contractRegister, startBlock) {
|
|
292
341
|
let fuelKind;
|
|
293
342
|
switch (kind) {
|
|
@@ -362,7 +411,11 @@ export {
|
|
|
362
411
|
buildTopicGetter,
|
|
363
412
|
alwaysIncludedBlockFields,
|
|
364
413
|
resolveFieldSelection,
|
|
414
|
+
compileAddressFilter,
|
|
415
|
+
buildAddressFilterBody,
|
|
416
|
+
buildAddressFilter,
|
|
365
417
|
buildEvmEventConfig,
|
|
418
|
+
buildSvmInstructionEventConfig,
|
|
366
419
|
buildFuelEventConfig,
|
|
367
420
|
}
|
|
368
421
|
/* paramMetaSchema Not a pure module */
|
package/src/EventUtils.res
CHANGED
|
@@ -45,8 +45,8 @@ let packEventIndex = (~blockNumber, ~logIndex) => {
|
|
|
45
45
|
// let logIndexMask = 65535->BigInt.fromInt
|
|
46
46
|
// let logIndex = packedEventIndex->BigInt.bitwiseAnd(logIndexMask)
|
|
47
47
|
// {
|
|
48
|
-
// blockNumber: blockNumber->BigInt.toString->
|
|
49
|
-
// logIndex: logIndex->BigInt.toString->
|
|
48
|
+
// blockNumber: blockNumber->BigInt.toString->Int.fromString->Option.getUnsafe,
|
|
49
|
+
// logIndex: logIndex->BigInt.toString->Int.fromString->Option.getUnsafe,
|
|
50
50
|
// }
|
|
51
51
|
// }
|
|
52
52
|
|
package/src/FetchState.res
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
type contractConfig = {
|
|
1
|
+
type contractConfig = {startBlock: option<int>}
|
|
2
2
|
|
|
3
|
-
type indexingAddress =
|
|
4
|
-
...Internal.indexingAddress,
|
|
5
|
-
effectiveStartBlock: int,
|
|
6
|
-
}
|
|
3
|
+
type indexingAddress = Internal.indexingContract
|
|
7
4
|
|
|
8
5
|
let deriveEffectiveStartBlock = (~registrationBlock: int, ~contractStartBlock: option<int>) => {
|
|
9
6
|
Pervasives.max(Pervasives.max(registrationBlock, 0), contractStartBlock->Option.getOr(0))
|
|
@@ -336,7 +333,7 @@ module OptimizedPartitions = {
|
|
|
336
333
|
let _ = newPartitions->Array.sort(ascSortFn)
|
|
337
334
|
|
|
338
335
|
let partitionsCount = newPartitions->Array.length
|
|
339
|
-
let idsInAscOrder =
|
|
336
|
+
let idsInAscOrder = Utils.Array.jsArrayCreate(partitionsCount)
|
|
340
337
|
let entities = Dict.make()
|
|
341
338
|
for idx in 0 to partitionsCount - 1 {
|
|
342
339
|
let p = newPartitions->Array.getUnsafe(idx)
|
|
@@ -639,7 +636,7 @@ let updateInternal = (
|
|
|
639
636
|
let maxBlockNumber = switch switch mutItemsRef.contents {
|
|
640
637
|
| Some(mutItems) => mutItems
|
|
641
638
|
| None => fetchState.buffer
|
|
642
|
-
}->
|
|
639
|
+
}->Array.get(fetchState.targetBufferSize - 1) {
|
|
643
640
|
| Some(item) => item->Internal.getItemBlockNumber
|
|
644
641
|
| None =>
|
|
645
642
|
switch optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
|
|
@@ -756,7 +753,6 @@ Returns OptimizedPartitions.t directly.
|
|
|
756
753
|
*/
|
|
757
754
|
let createPartitionsFromIndexingAddresses = (
|
|
758
755
|
~registeringContractsByContract: dict<dict<indexingAddress>>,
|
|
759
|
-
~contractConfigs: dict<contractConfig>,
|
|
760
756
|
~dynamicContracts: Utils.Set.t<string>,
|
|
761
757
|
~normalSelection: selection,
|
|
762
758
|
~maxAddrInPartition: int,
|
|
@@ -778,9 +774,6 @@ OptimizedPartitions.t => {
|
|
|
778
774
|
let addresses =
|
|
779
775
|
registeringContracts->Dict.keysToArray->(Utils.magic: array<string> => array<Address.t>)
|
|
780
776
|
|
|
781
|
-
// Can unsafely get it, because we already filtered out the contracts
|
|
782
|
-
// that don't have any events to fetch
|
|
783
|
-
let contractConfig = contractConfigs->Dict.getUnsafe(contractName)
|
|
784
777
|
let isDynamic = dynamicContracts->Utils.Set.has(contractName)
|
|
785
778
|
let partitions = isDynamic ? dynamicPartitions : nonDynamicPartitions
|
|
786
779
|
|
|
@@ -802,30 +795,23 @@ OptimizedPartitions.t => {
|
|
|
802
795
|
let maybeNextStartBlockKey =
|
|
803
796
|
ascKeys->Array.getUnsafe(idx + 1)->(Utils.magic: string => option<string>)
|
|
804
797
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
if shouldJoinCurrentStartBlock {
|
|
823
|
-
addressesRef :=
|
|
824
|
-
addressesRef.contents->Array.concat(byStartBlock->Dict.getUnsafe(nextStartBlockKey))
|
|
825
|
-
false
|
|
826
|
-
} else {
|
|
827
|
-
true
|
|
828
|
-
}
|
|
798
|
+
let shouldAllocateNewPartition = switch maybeNextStartBlockKey {
|
|
799
|
+
| None => true
|
|
800
|
+
| Some(nextStartBlockKey) => {
|
|
801
|
+
let nextStartBlock = nextStartBlockKey->Int.fromString->Option.getUnsafe
|
|
802
|
+
let shouldJoinCurrentStartBlock =
|
|
803
|
+
nextStartBlock - startBlockRef.contents < OptimizedPartitions.tooFarBlockRange
|
|
804
|
+
|
|
805
|
+
// Addresses with different start blocks within range share a partition;
|
|
806
|
+
// events before each address's effectiveStartBlock are dropped on the
|
|
807
|
+
// client side (EventRouter for the srcAddress, the event's
|
|
808
|
+
// clientAddressFilter for address-valued params).
|
|
809
|
+
if shouldJoinCurrentStartBlock {
|
|
810
|
+
addressesRef :=
|
|
811
|
+
addressesRef.contents->Array.concat(byStartBlock->Dict.getUnsafe(nextStartBlockKey))
|
|
812
|
+
false
|
|
813
|
+
} else {
|
|
814
|
+
true
|
|
829
815
|
}
|
|
830
816
|
}
|
|
831
817
|
}
|
|
@@ -907,15 +893,10 @@ OptimizedPartitions.t => {
|
|
|
907
893
|
}
|
|
908
894
|
}
|
|
909
895
|
|
|
910
|
-
let nextContractName =
|
|
911
|
-
nextP.addressesByContractName->Dict.keysToArray->Utils.Array.firstUnsafe
|
|
912
|
-
let hasFilterByAddresses = (
|
|
913
|
-
contractConfigs->Dict.getUnsafe(nextContractName)
|
|
914
|
-
).filterByAddresses
|
|
915
896
|
let isTooFar = currentPBlock + OptimizedPartitions.tooFarBlockRange < nextPBlock
|
|
916
897
|
|
|
917
|
-
if isTooFar
|
|
918
|
-
// Too far
|
|
898
|
+
if isTooFar {
|
|
899
|
+
// Too far: mergeBlock on current, merge addresses into next
|
|
919
900
|
mergedNonDynamic
|
|
920
901
|
->Array.push({
|
|
921
902
|
...currentP,
|
|
@@ -927,7 +908,7 @@ OptimizedPartitions.t => {
|
|
|
927
908
|
addressesByContractName: mergedAddresses,
|
|
928
909
|
}
|
|
929
910
|
} else {
|
|
930
|
-
// Close
|
|
911
|
+
// Close: push next's addresses into current
|
|
931
912
|
currentPRef := {
|
|
932
913
|
...currentP,
|
|
933
914
|
addressesByContractName: mergedAddresses,
|
|
@@ -968,12 +949,15 @@ let registerDynamicContracts = (
|
|
|
968
949
|
let indexingAddresses = fetchState.indexingAddresses
|
|
969
950
|
let registeringContractsByContract: dict<dict<indexingAddress>> = Dict.make()
|
|
970
951
|
let earliestRegisteringEventBlockNumber = ref(%raw(`Infinity`))
|
|
971
|
-
let hasDCWithFilterByAddresses = ref(false)
|
|
972
952
|
// Addresses registered for contracts without matching events. These are not
|
|
973
953
|
// added to partitions, but they are tracked on fetchState.indexingAddresses
|
|
974
954
|
// so that later conflicting registrations are detected, and are persisted
|
|
975
955
|
// to envio_addresses so they can be picked up on restart with updated config.
|
|
976
956
|
let noEventsAddresses: dict<indexingAddress> = Dict.make()
|
|
957
|
+
// Batch-level view of all addresses registered so far (across contracts,
|
|
958
|
+
// including no-events ones), so two contracts registering the same address
|
|
959
|
+
// within one batch conflict the same way as against indexingAddresses.
|
|
960
|
+
let registeringAddresses: dict<indexingAddress> = Dict.make()
|
|
977
961
|
|
|
978
962
|
for itemIdx in 0 to items->Array.length - 1 {
|
|
979
963
|
let item = items->Array.getUnsafe(itemIdx)
|
|
@@ -987,7 +971,7 @@ let registerDynamicContracts = (
|
|
|
987
971
|
let shouldRemove = ref(false)
|
|
988
972
|
|
|
989
973
|
switch fetchState.contractConfigs->Utils.Dict.dangerouslyGetNonOption(dc.contractName) {
|
|
990
|
-
| Some({
|
|
974
|
+
| Some({startBlock: contractStartBlock}) =>
|
|
991
975
|
let dcWithStartBlock: indexingAddress = {
|
|
992
976
|
address: dc.address,
|
|
993
977
|
contractName: dc.contractName,
|
|
@@ -1021,9 +1005,7 @@ let registerDynamicContracts = (
|
|
|
1021
1005
|
}
|
|
1022
1006
|
shouldRemove := true
|
|
1023
1007
|
| None =>
|
|
1024
|
-
let
|
|
1025
|
-
registeringContractsByContract->Utils.Dict.getOrInsertEmptyDict(dc.contractName)
|
|
1026
|
-
let shouldUpdate = switch registeringContracts->Utils.Dict.dangerouslyGetNonOption(
|
|
1008
|
+
let shouldUpdate = switch registeringAddresses->Utils.Dict.dangerouslyGetNonOption(
|
|
1027
1009
|
dc.address->Address.toString,
|
|
1028
1010
|
) {
|
|
1029
1011
|
| Some(registeringContract) if registeringContract.contractName != dc.contractName =>
|
|
@@ -1036,9 +1018,7 @@ let registerDynamicContracts = (
|
|
|
1036
1018
|
// FIXME: This unsafely relies on the asc order of the items
|
|
1037
1019
|
// which is 99% true, but there were cases when the source ordering was wrong
|
|
1038
1020
|
false
|
|
1039
|
-
| None =>
|
|
1040
|
-
hasDCWithFilterByAddresses := hasDCWithFilterByAddresses.contents || filterByAddresses
|
|
1041
|
-
true
|
|
1021
|
+
| None => true
|
|
1042
1022
|
}
|
|
1043
1023
|
if shouldUpdate {
|
|
1044
1024
|
earliestRegisteringEventBlockNumber :=
|
|
@@ -1046,7 +1026,10 @@ let registerDynamicContracts = (
|
|
|
1046
1026
|
earliestRegisteringEventBlockNumber.contents,
|
|
1047
1027
|
dcWithStartBlock.effectiveStartBlock,
|
|
1048
1028
|
)
|
|
1049
|
-
|
|
1029
|
+
registeringContractsByContract
|
|
1030
|
+
->Utils.Dict.getOrInsertEmptyDict(dc.contractName)
|
|
1031
|
+
->Dict.set(dc.address->Address.toString, dcWithStartBlock)
|
|
1032
|
+
registeringAddresses->Dict.set(dc.address->Address.toString, dcWithStartBlock)
|
|
1050
1033
|
} else {
|
|
1051
1034
|
shouldRemove := true
|
|
1052
1035
|
}
|
|
@@ -1073,11 +1056,14 @@ let registerDynamicContracts = (
|
|
|
1073
1056
|
}
|
|
1074
1057
|
shouldRemove := true
|
|
1075
1058
|
| None =>
|
|
1076
|
-
switch
|
|
1059
|
+
switch registeringAddresses->Utils.Dict.dangerouslyGetNonOption(
|
|
1077
1060
|
dc.address->Address.toString,
|
|
1078
1061
|
) {
|
|
1079
|
-
| Some(
|
|
1080
|
-
|
|
1062
|
+
| Some(existingContract) =>
|
|
1063
|
+
if existingContract.contractName != dc.contractName {
|
|
1064
|
+
fetchState->warnDifferentContractType(~existingContract, ~dc=dcAsIndexingAddress)
|
|
1065
|
+
}
|
|
1066
|
+
// Otherwise already queued for persistence by an earlier item in this batch.
|
|
1081
1067
|
shouldRemove := true
|
|
1082
1068
|
| None =>
|
|
1083
1069
|
let logger = Logging.createChild(
|
|
@@ -1092,6 +1078,7 @@ let registerDynamicContracts = (
|
|
|
1092
1078
|
// skip partition registration since there's nothing to fetch.
|
|
1093
1079
|
logger->Logging.childWarn(`Persisting contract registration without fetching: Contract doesn't have any events to fetch. It'll be picked up on restart if you add events for the contract.`)
|
|
1094
1080
|
noEventsAddresses->Dict.set(dc.address->Address.toString, dcAsIndexingAddress)
|
|
1081
|
+
registeringAddresses->Dict.set(dc.address->Address.toString, dcAsIndexingAddress)
|
|
1095
1082
|
}
|
|
1096
1083
|
}
|
|
1097
1084
|
}
|
|
@@ -1209,7 +1196,6 @@ let registerDynamicContracts = (
|
|
|
1209
1196
|
|
|
1210
1197
|
let optimizedPartitions = createPartitionsFromIndexingAddresses(
|
|
1211
1198
|
~registeringContractsByContract,
|
|
1212
|
-
~contractConfigs=fetchState.contractConfigs,
|
|
1213
1199
|
~dynamicContracts=dynamicContractsRef.contents,
|
|
1214
1200
|
~normalSelection=fetchState.normalSelection,
|
|
1215
1201
|
~maxAddrInPartition=fetchState.optimizedPartitions.maxAddrInPartition,
|
|
@@ -1236,6 +1222,20 @@ let handleQueryResult = (
|
|
|
1236
1222
|
~latestFetchedBlock: blockNumberAndTimestamp,
|
|
1237
1223
|
~newItems,
|
|
1238
1224
|
): t => {
|
|
1225
|
+
// Drop events an address-param filter rejects. A merged partition may
|
|
1226
|
+
// over-fetch a wildcard event whose indexed address param references an
|
|
1227
|
+
// address registered after the log's block; `clientAddressFilter` is the
|
|
1228
|
+
// param-level analogue of EventRouter's srcAddress effectiveStartBlock check.
|
|
1229
|
+
let newItems = newItems->Array.filter(item =>
|
|
1230
|
+
switch item {
|
|
1231
|
+
| Internal.Event({eventConfig, event, blockNumber}) =>
|
|
1232
|
+
switch eventConfig.clientAddressFilter {
|
|
1233
|
+
| Some(filter) => filter(event, blockNumber, fetchState.indexingAddresses)
|
|
1234
|
+
| None => true
|
|
1235
|
+
}
|
|
1236
|
+
| _ => true
|
|
1237
|
+
}
|
|
1238
|
+
)
|
|
1239
1239
|
fetchState->updateInternal(
|
|
1240
1240
|
~optimizedPartitions=fetchState.optimizedPartitions->OptimizedPartitions.handleQueryResponse(
|
|
1241
1241
|
~query,
|
|
@@ -1508,7 +1508,7 @@ let getNextQuery = (
|
|
|
1508
1508
|
}
|
|
1509
1509
|
|
|
1510
1510
|
let hasReadyItem = ({buffer} as fetchState: t) => {
|
|
1511
|
-
switch buffer->
|
|
1511
|
+
switch buffer->Array.get(0) {
|
|
1512
1512
|
| Some(item) => item->Internal.getItemBlockNumber <= fetchState->bufferBlockNumber
|
|
1513
1513
|
| None => false
|
|
1514
1514
|
}
|
|
@@ -1519,7 +1519,7 @@ let getReadyItemsCount = (fetchState: t, ~targetSize: int, ~fromItem) => {
|
|
|
1519
1519
|
let acc = ref(0)
|
|
1520
1520
|
let isFinished = ref(false)
|
|
1521
1521
|
while !isFinished.contents {
|
|
1522
|
-
switch fetchState.buffer->
|
|
1522
|
+
switch fetchState.buffer->Array.get(fromItem + acc.contents) {
|
|
1523
1523
|
| Some(item) =>
|
|
1524
1524
|
let itemBlockNumber = item->Internal.getItemBlockNumber
|
|
1525
1525
|
if itemBlockNumber <= readyBlockNumber.contents {
|
|
@@ -1563,15 +1563,14 @@ let make = (
|
|
|
1563
1563
|
let normalEventConfigs = []
|
|
1564
1564
|
let contractNamesWithNormalEvents = Utils.Set.make()
|
|
1565
1565
|
let indexingAddresses = Dict.make()
|
|
1566
|
-
let contractConfigs = Dict.make()
|
|
1566
|
+
let contractConfigs: dict<contractConfig> = Dict.make()
|
|
1567
1567
|
|
|
1568
1568
|
eventConfigs->Array.forEach(ec => {
|
|
1569
1569
|
switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(ec.contractName) {
|
|
1570
|
-
| Some({
|
|
1570
|
+
| Some({startBlock}) =>
|
|
1571
1571
|
contractConfigs->Dict.set(
|
|
1572
1572
|
ec.contractName,
|
|
1573
1573
|
{
|
|
1574
|
-
filterByAddresses: filterByAddresses || ec.filterByAddresses,
|
|
1575
1574
|
startBlock: switch (startBlock, ec.startBlock) {
|
|
1576
1575
|
| (Some(a), Some(b)) => Some(Pervasives.min(a, b))
|
|
1577
1576
|
| (Some(_) as s, None) | (None, Some(_) as s) => s
|
|
@@ -1583,7 +1582,6 @@ let make = (
|
|
|
1583
1582
|
contractConfigs->Dict.set(
|
|
1584
1583
|
ec.contractName,
|
|
1585
1584
|
{
|
|
1586
|
-
filterByAddresses: ec.filterByAddresses,
|
|
1587
1585
|
startBlock: ec.startBlock,
|
|
1588
1586
|
},
|
|
1589
1587
|
)
|
|
@@ -1663,7 +1661,6 @@ let make = (
|
|
|
1663
1661
|
|
|
1664
1662
|
let optimizedPartitions = createPartitionsFromIndexingAddresses(
|
|
1665
1663
|
~registeringContractsByContract,
|
|
1666
|
-
~contractConfigs,
|
|
1667
1664
|
~dynamicContracts,
|
|
1668
1665
|
~normalSelection,
|
|
1669
1666
|
~maxAddrInPartition,
|
|
@@ -1866,7 +1863,6 @@ let rollback = (fetchState: t, ~targetBlockNumber) => {
|
|
|
1866
1863
|
// Step 3: Recreate partitions from deleted partition addresses
|
|
1867
1864
|
let optimizedPartitions = createPartitionsFromIndexingAddresses(
|
|
1868
1865
|
~registeringContractsByContract,
|
|
1869
|
-
~contractConfigs=fetchState.contractConfigs,
|
|
1870
1866
|
~dynamicContracts=fetchState.optimizedPartitions.dynamicContracts,
|
|
1871
1867
|
~normalSelection=fetchState.normalSelection,
|
|
1872
1868
|
~maxAddrInPartition=fetchState.optimizedPartitions.maxAddrInPartition,
|
|
@@ -1951,7 +1947,7 @@ let isReadyToEnterReorgThreshold = ({endBlock, blockLag, buffer, knownHeight} as
|
|
|
1951
1947
|
|
|
1952
1948
|
let sortForUnorderedBatch = {
|
|
1953
1949
|
let hasFullBatch = ({buffer} as fetchState: t, ~batchSizeTarget) => {
|
|
1954
|
-
switch buffer->
|
|
1950
|
+
switch buffer->Array.get(batchSizeTarget - 1) {
|
|
1955
1951
|
| Some(item) => item->Internal.getItemBlockNumber <= fetchState->bufferBlockNumber
|
|
1956
1952
|
| None => false
|
|
1957
1953
|
}
|
|
@@ -1966,7 +1962,7 @@ let sortForUnorderedBatch = {
|
|
|
1966
1962
|
if totalRange <= 0 {
|
|
1967
1963
|
0.
|
|
1968
1964
|
} else {
|
|
1969
|
-
let progress = switch fetchState.buffer->
|
|
1965
|
+
let progress = switch fetchState.buffer->Array.get(0) {
|
|
1970
1966
|
| Some(item) => item->Internal.getItemBlockNumber - firstEventBlock
|
|
1971
1967
|
| None => fetchState->bufferBlockNumber - firstEventBlock
|
|
1972
1968
|
}
|
|
@@ -2001,7 +1997,7 @@ let sortForUnorderedBatch = {
|
|
|
2001
1997
|
|
|
2002
1998
|
let getProgressBlockNumberAt = ({buffer} as fetchState: t, ~index) => {
|
|
2003
1999
|
let bufferBlockNumber = fetchState->bufferBlockNumber
|
|
2004
|
-
switch buffer->
|
|
2000
|
+
switch buffer->Array.get(index) {
|
|
2005
2001
|
| Some(item) if bufferBlockNumber >= item->Internal.getItemBlockNumber =>
|
|
2006
2002
|
item->Internal.getItemBlockNumber - 1
|
|
2007
2003
|
| _ => bufferBlockNumber
|