envio 3.15.0 → 3.16.0-subgraph
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -34
- package/evm.schema.json +11 -2
- package/fuel.schema.json +10 -1
- package/index.d.ts +6 -0
- package/licenses/README.md +1 -1
- package/package.json +10 -9
- package/src/Batch.res.mjs +5 -5
- package/src/BatchProcessing.res +1 -0
- package/src/BatchProcessing.res.mjs +1 -0
- package/src/Bin.res +7 -0
- package/src/Bin.res.mjs +8 -0
- package/src/ChainFetching.res +450 -16
- package/src/ChainFetching.res.mjs +403 -32
- package/src/ChainState.res +124 -7
- package/src/ChainState.res.mjs +128 -67
- package/src/ChainState.resi +26 -0
- package/src/Clock.res +57 -0
- package/src/Clock.res.mjs +72 -0
- package/src/Config.res +31 -3
- package/src/Config.res.mjs +15 -4
- package/src/ContractRegisterContext.res +3 -6
- package/src/ContractRegisterContext.res.mjs +4 -2
- package/src/Core.res +95 -36
- package/src/Core.res.mjs +90 -1
- package/src/CrossChainState.res +12 -2
- package/src/CrossChainState.res.mjs +3 -3
- package/src/Ecosystem.res +7 -4
- package/src/Ecosystem.res.mjs +8 -8
- package/src/EffectCacheLookup.res +98 -0
- package/src/EffectCacheLookup.res.mjs +116 -0
- package/src/EffectState.res +10 -2
- package/src/EffectState.res.mjs +8 -4
- package/src/EffectState.resi +3 -1
- package/src/EntityId.res +2 -7
- package/src/EntityId.res.mjs +1 -8
- package/src/EntityTables.res +4 -1
- package/src/EntityTables.res.mjs +1 -1
- package/src/Env.res +20 -0
- package/src/Env.res.mjs +16 -0
- package/src/EventProcessing.res +38 -1
- package/src/EventProcessing.res.mjs +28 -1
- package/src/FetchState.res +408 -73
- package/src/FetchState.res.mjs +361 -91
- package/src/FinalizeBackfill.res +2 -4
- package/src/FinalizeBackfill.res.mjs +3 -4
- package/src/HandlerLoader.res +39 -15
- package/src/HandlerLoader.res.mjs +27 -8
- package/src/HandlerRegister.res +4 -0
- package/src/HandlerRegister.res.mjs +5 -2
- package/src/HandlerRegister.resi +2 -0
- package/src/InMemoryTable.res +17 -16
- package/src/InMemoryTable.res.mjs +14 -15
- package/src/IndexerState.res +28 -4
- package/src/IndexerState.res.mjs +19 -6
- package/src/IndexerState.resi +4 -0
- package/src/Internal.res +61 -49
- package/src/Internal.res.mjs +36 -80
- package/src/LoadLayer.res +54 -15
- package/src/LoadLayer.res.mjs +75 -45
- package/src/LoadLayer.resi +26 -0
- package/src/Main.res +14 -1
- package/src/Main.res.mjs +4 -3
- package/src/Persistence.res +3 -23
- package/src/Persistence.res.mjs +3 -3
- package/src/PreloadLookahead.res +202 -0
- package/src/PreloadLookahead.res.mjs +218 -0
- package/src/Rollback.res +0 -1
- package/src/Rollback.res.mjs +1 -1
- package/src/RunScope.res +3 -0
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +1 -1
- package/src/SimulateItems.res +42 -26
- package/src/SimulateItems.res.mjs +40 -16
- package/src/StagedRows.res +106 -0
- package/src/StagedRows.res.mjs +102 -0
- package/src/Staging.res +32 -14
- package/src/Staging.res.mjs +17 -20
- package/src/Storage.res +303 -948
- package/src/Storage.res.mjs +229 -708
- package/src/SubgraphLog.res +19 -0
- package/src/SubgraphLog.res.mjs +26 -0
- package/src/Supervisor.res +75 -56
- package/src/Supervisor.res.mjs +55 -26
- package/src/SyncWrites.res +107 -0
- package/src/SyncWrites.res.mjs +98 -0
- package/src/TestIndexer.res +22 -27
- package/src/TestIndexer.res.mjs +20 -17
- package/src/Throttler.res +15 -8
- package/src/Throttler.res.mjs +9 -6
- package/src/Throttler.resi +1 -1
- package/src/UserContext.res +419 -46
- package/src/UserContext.res.mjs +318 -30
- package/src/Utils.res +17 -6
- package/src/Utils.res.mjs +12 -6
- package/src/Writing.res +0 -1
- package/src/Writing.res.mjs +1 -1
- package/src/bindings/ClickHouse.res +0 -322
- package/src/bindings/ClickHouse.res.mjs +0 -338
- package/src/bindings/StorageClient.res +108 -174
- package/src/bindings/StorageClient.res.mjs +19 -8
- package/src/bindings/Vitest.res +0 -26
- package/src/bindings/Vitest.res.mjs +0 -3
- package/src/db/Table.res +24 -150
- package/src/db/Table.res.mjs +38 -272
- package/src/sources/AddressSet.res +2 -0
- package/src/sources/AddressStore.res +3 -0
- package/src/sources/CallSource.res +274 -0
- package/src/sources/CallSource.res.mjs +196 -0
- package/src/sources/ChainSources.res +2 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +10 -1
- package/src/sources/EvmChain.res.mjs +6 -3
- package/src/sources/EvmHyperSyncSource.res +2 -2
- package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
- package/src/sources/EvmRpcClient.res +13 -3
- package/src/sources/EvmRpcClient.res.mjs +4 -3
- package/src/sources/EvmRpcWs.res +4 -3
- package/src/sources/EvmRpcWs.res.mjs +2 -2
- package/src/sources/HeightFeed.res +31 -10
- package/src/sources/HeightFeed.res.mjs +10 -6
- package/src/sources/HeightStream.res +32 -17
- package/src/sources/HeightStream.res.mjs +10 -10
- package/src/sources/HyperSync.res +2 -1
- package/src/sources/HyperSync.res.mjs +2 -1
- package/src/sources/HyperSyncSSE.res +4 -6
- package/src/sources/HyperSyncSSE.res.mjs +2 -2
- package/src/sources/RpcSource.res +10 -1
- package/src/sources/RpcSource.res.mjs +4 -3
- package/src/sources/Source.res +3 -0
- package/src/sources/SourceManager.res +84 -77
- package/src/sources/SourceManager.res.mjs +17 -20
- package/src/sources/SourceManager.resi +3 -4
- package/src/sources/StartBlockResolver.res +1 -0
- package/src/sources/StartBlockResolver.res.mjs +3 -2
- package/src/sources/SvmHyperSyncSource.res +2 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/src/subgraph/abi-types.ts +84 -0
- package/src/subgraph/aggregations.ts +745 -0
- package/src/subgraph/as-package.ts +143 -0
- package/src/subgraph/assemblyscript-regex.ts +67 -0
- package/src/subgraph/assemblyscript.ts +731 -0
- package/src/subgraph/blocks.ts +398 -0
- package/src/subgraph/calls-source.ts +702 -0
- package/src/subgraph/calls.ts +258 -0
- package/src/subgraph/conformance.ts +106 -0
- package/src/subgraph/errors.ts +85 -0
- package/src/subgraph/graft.ts +73 -0
- package/src/subgraph/graph-cli-worker.mjs +35 -0
- package/src/subgraph/graph-cli.ts +900 -0
- package/src/subgraph/graph-node-decimal.ts +199 -0
- package/src/subgraph/graph-ts-enums.ts +28 -0
- package/src/subgraph/graph-ts-types/VERSION +2 -0
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
- package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
- package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
- package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
- package/src/subgraph/graph-ts-types/index.d.ts +102 -0
- package/src/subgraph/graph-ts.ts +4339 -0
- package/src/subgraph/hosts.ts +554 -0
- package/src/subgraph/log.ts +28 -0
- package/src/subgraph/receipts.ts +184 -0
- package/src/subgraph/register-slots.ts +93 -0
- package/src/subgraph/rollup.ts +109 -0
- package/src/subgraph/rpc.ts +337 -0
- package/src/subgraph/runtime.ts +2059 -0
- package/src/subgraph/scope.ts +176 -0
- package/src/subgraph/stats.ts +42 -0
- package/src/subgraph/template-instances.ts +66 -0
- package/src/subgraph/toolchain.ts +327 -0
- package/src/subgraph/transient.ts +176 -0
- package/svm.schema.json +11 -2
- package/src/PgWriting.res +0 -36
- package/src/PgWriting.res.mjs +0 -34
- package/src/db/IndexDefinition.res +0 -47
- package/src/db/IndexDefinition.res.mjs +0 -67
package/src/FetchState.res
CHANGED
|
@@ -864,6 +864,22 @@ module OptimizedPartitions = {
|
|
|
864
864
|
}
|
|
865
865
|
}
|
|
866
866
|
|
|
867
|
+
// Subgraph mode: where a dynamically registered address was registered and in
|
|
868
|
+
// which round of its block (1 for a data source created by the block's own
|
|
869
|
+
// triggers, 2 for one created by those, and so on).
|
|
870
|
+
type creationBlock = {block: int, round: int}
|
|
871
|
+
|
|
872
|
+
// When a contract's addresses leave the server-side filter. A switched contract
|
|
873
|
+
// is fetched by the single address-free partition and gated against the address
|
|
874
|
+
// store on our side. The switch is sticky for the run.
|
|
875
|
+
type clientFilterPolicy = {
|
|
876
|
+
// Past this many registered addresses. None never switches on count alone.
|
|
877
|
+
addressThreshold: option<int>,
|
|
878
|
+
// Every dynamic contract, whatever its address count. Keeps a chain at one
|
|
879
|
+
// query per block, of one shape, however many contracts it registers.
|
|
880
|
+
allDynamicContracts: bool,
|
|
881
|
+
}
|
|
882
|
+
|
|
867
883
|
type t = {
|
|
868
884
|
optimizedPartitions: OptimizedPartitions.t,
|
|
869
885
|
startBlock: int,
|
|
@@ -879,6 +895,7 @@ type t = {
|
|
|
879
895
|
// How much blocks behind the head we should query
|
|
880
896
|
// Needed to query before entering reorg threshold
|
|
881
897
|
blockLag: int,
|
|
898
|
+
blockThrottle: int,
|
|
882
899
|
// Buffer of items ordered from earliest to latest
|
|
883
900
|
buffer: array<Internal.item>,
|
|
884
901
|
// Caps how far ahead onBlock items are pre-generated (set to 2x the batch
|
|
@@ -890,10 +907,17 @@ type t = {
|
|
|
890
907
|
onBlockRegistrations: array<Internal.onBlockRegistration>,
|
|
891
908
|
knownHeight: int,
|
|
892
909
|
firstEventBlock: option<int>,
|
|
893
|
-
|
|
894
|
-
//
|
|
895
|
-
// contract
|
|
896
|
-
|
|
910
|
+
clientFilterPolicy: clientFilterPolicy,
|
|
911
|
+
// Subgraph mode only: the block each dynamically registered address was
|
|
912
|
+
// registered in, keyed by contract and lowercase address, until fetching
|
|
913
|
+
// passes it. Its events in that block run after the rest of the block, as
|
|
914
|
+
// graph-node runs a new data source's creation-block triggers.
|
|
915
|
+
creationBlocks?: dict<creationBlock>,
|
|
916
|
+
// Set when an onBlock registration has a contractRegister: the last block
|
|
917
|
+
// whose block-handler register passes have run and whose registrations are
|
|
918
|
+
// applied. No block item past it is generated, so none is processed before
|
|
919
|
+
// the data sources its block created are fetched.
|
|
920
|
+
blockRegisterThrough?: int,
|
|
897
921
|
}
|
|
898
922
|
|
|
899
923
|
// The latest block whose items are all in the buffer: the lowest partition
|
|
@@ -983,6 +1007,65 @@ let compareTiebreak = (a: Internal.item, b: Internal.item): int => {
|
|
|
983
1007
|
}
|
|
984
1008
|
}
|
|
985
1009
|
|
|
1010
|
+
// Within a block, graph-node runs a subgraph's triggers in this order: logs and
|
|
1011
|
+
// calls by transaction — a transaction's logs, then its calls in trace order —
|
|
1012
|
+
// then the block triggers of `filter: call` handlers, one per call, then the
|
|
1013
|
+
// block handlers. A call item is told apart by its rank (see
|
|
1014
|
+
// `Internal.getItemCallRank`), and only a run that has one pays for this
|
|
1015
|
+
// comparison. Creation-block items (rank 4) keep their place after everything
|
|
1016
|
+
// else, ordered among themselves by the same transaction rule. A `once`
|
|
1017
|
+
// handler's item (rank -1) comes before all of them.
|
|
1018
|
+
let blockOrderRank = (item: Internal.item) =>
|
|
1019
|
+
switch item->Internal.getItemCreationRound {
|
|
1020
|
+
| Some(round) => 3 + round
|
|
1021
|
+
| None =>
|
|
1022
|
+
if item->Internal.getItemKind !== 0 {
|
|
1023
|
+
item->Internal.itemRunsFirst ? -1 : 3
|
|
1024
|
+
} else if item->Internal.getItemCallRank === Some(2) {
|
|
1025
|
+
2
|
|
1026
|
+
} else {
|
|
1027
|
+
0
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
let compareWithCalls = (a: Internal.item, b: Internal.item): int => {
|
|
1032
|
+
let ra = blockOrderRank(a)
|
|
1033
|
+
let rb = blockOrderRank(b)
|
|
1034
|
+
if ra !== rb {
|
|
1035
|
+
ra < rb ? -1 : 1
|
|
1036
|
+
} else if ra === 3 || ra === -1 {
|
|
1037
|
+
// Block handlers: as before.
|
|
1038
|
+
let la = a->Internal.getItemLogIndex
|
|
1039
|
+
let lb = b->Internal.getItemLogIndex
|
|
1040
|
+
if la != lb {
|
|
1041
|
+
la < lb ? -1 : 1
|
|
1042
|
+
} else {
|
|
1043
|
+
compareTiebreak(a, b)
|
|
1044
|
+
}
|
|
1045
|
+
} else {
|
|
1046
|
+
let ta = a->Internal.getItemTransactionIndex
|
|
1047
|
+
let tb = b->Internal.getItemTransactionIndex
|
|
1048
|
+
if ta != tb {
|
|
1049
|
+
ta < tb ? -1 : 1
|
|
1050
|
+
} else {
|
|
1051
|
+
// A transaction's logs precede its calls.
|
|
1052
|
+
let ca = a->Internal.getItemCallRank->Option.isSome ? 1 : 0
|
|
1053
|
+
let cb = b->Internal.getItemCallRank->Option.isSome ? 1 : 0
|
|
1054
|
+
if ca !== cb {
|
|
1055
|
+
ca < cb ? -1 : 1
|
|
1056
|
+
} else {
|
|
1057
|
+
let la = a->Internal.getItemLogIndex
|
|
1058
|
+
let lb = b->Internal.getItemLogIndex
|
|
1059
|
+
if la != lb {
|
|
1060
|
+
la < lb ? -1 : 1
|
|
1061
|
+
} else {
|
|
1062
|
+
compareTiebreak(a, b)
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
986
1069
|
// Total order on buffer items: block, then item kind, then the ecosystem's
|
|
987
1070
|
// within-block order, then registration index. Returns a plain int (-1/0/1)
|
|
988
1071
|
// with explicit field comparisons so it can be called directly from the
|
|
@@ -994,15 +1077,32 @@ let compareTiebreak = (a: Internal.item, b: Internal.item): int => {
|
|
|
994
1077
|
// block's handlers by construction. A sentinel log index for block items
|
|
995
1078
|
// would put the same guarantee at the mercy of how large an ecosystem's key
|
|
996
1079
|
// grows — which is how SVM, keyed by transaction index, came to run slot
|
|
997
|
-
// handlers ahead of most of a slot's instructions.
|
|
1080
|
+
// handlers ahead of most of a slot's instructions. A subgraph's `once` handler
|
|
1081
|
+
// is the exception: it runs ahead of its block's events.
|
|
998
1082
|
let compareBufferItem = (a: Internal.item, b: Internal.item): int => {
|
|
999
1083
|
let ba = a->Internal.getItemBlockNumber
|
|
1000
1084
|
let bb = b->Internal.getItemBlockNumber
|
|
1001
1085
|
if ba != bb {
|
|
1002
1086
|
ba < bb ? -1 : 1
|
|
1087
|
+
} else if Internal.callOrderingActive.contents {
|
|
1088
|
+
compareWithCalls(a, b)
|
|
1003
1089
|
} else {
|
|
1004
|
-
let ka = a->Internal.
|
|
1005
|
-
|
|
1090
|
+
let ka = switch a->Internal.getItemCreationRound {
|
|
1091
|
+
| Some(round) => 1 + round
|
|
1092
|
+
| None =>
|
|
1093
|
+
switch a->Internal.getItemKind {
|
|
1094
|
+
| 0 => 0
|
|
1095
|
+
| kind => a->Internal.itemRunsFirst ? -1 : kind
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
let kb = switch b->Internal.getItemCreationRound {
|
|
1099
|
+
| Some(round) => 1 + round
|
|
1100
|
+
| None =>
|
|
1101
|
+
switch b->Internal.getItemKind {
|
|
1102
|
+
| 0 => 0
|
|
1103
|
+
| kind => b->Internal.itemRunsFirst ? -1 : kind
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1006
1106
|
if ka !== kb {
|
|
1007
1107
|
ka < kb ? -1 : 1
|
|
1008
1108
|
} else {
|
|
@@ -1024,6 +1124,7 @@ let compareBufferItem = (a: Internal.item, b: Internal.item): int => {
|
|
|
1024
1124
|
let isSameLog = (a: Internal.item, b: Internal.item): bool =>
|
|
1025
1125
|
a->Internal.getItemKind === 0 &&
|
|
1026
1126
|
b->Internal.getItemKind === 0 &&
|
|
1127
|
+
a->Internal.getItemCallRank === b->Internal.getItemCallRank &&
|
|
1027
1128
|
a->Internal.getItemBlockNumber === b->Internal.getItemBlockNumber &&
|
|
1028
1129
|
a->Internal.getItemLogIndex === b->Internal.getItemLogIndex &&
|
|
1029
1130
|
switch (a->Internal.getItemOrderPath, b->Internal.getItemOrderPath) {
|
|
@@ -1177,6 +1278,10 @@ let updateInternal = (
|
|
|
1177
1278
|
},
|
|
1178
1279
|
knownHeight,
|
|
1179
1280
|
)
|
|
1281
|
+
let maxBlockNumber = switch fetchState.blockRegisterThrough {
|
|
1282
|
+
| Some(through) => Pervasives.min(maxBlockNumber, through)
|
|
1283
|
+
| None => maxBlockNumber
|
|
1284
|
+
}
|
|
1180
1285
|
appendOnBlockItems(
|
|
1181
1286
|
~mutItems=blockItems,
|
|
1182
1287
|
~onBlockRegistrations,
|
|
@@ -1197,6 +1302,7 @@ let updateInternal = (
|
|
|
1197
1302
|
optimizedPartitions,
|
|
1198
1303
|
latestOnBlockBlockNumber,
|
|
1199
1304
|
blockLag,
|
|
1305
|
+
blockThrottle: fetchState.blockThrottle,
|
|
1200
1306
|
knownHeight,
|
|
1201
1307
|
// Single merge point: fold any onBlock items into the sorted base buffer.
|
|
1202
1308
|
buffer: switch blockItems {
|
|
@@ -1204,7 +1310,9 @@ let updateInternal = (
|
|
|
1204
1310
|
| blockItems => base->mergeIntoBuffer(blockItems)
|
|
1205
1311
|
},
|
|
1206
1312
|
firstEventBlock: fetchState.firstEventBlock,
|
|
1207
|
-
|
|
1313
|
+
clientFilterPolicy: fetchState.clientFilterPolicy,
|
|
1314
|
+
creationBlocks: ?fetchState.creationBlocks,
|
|
1315
|
+
blockRegisterThrough: ?fetchState.blockRegisterThrough,
|
|
1208
1316
|
}
|
|
1209
1317
|
|
|
1210
1318
|
updatedFetchState
|
|
@@ -1232,22 +1340,40 @@ type notice =
|
|
|
1232
1340
|
requestedFromBlock: int,
|
|
1233
1341
|
})
|
|
1234
1342
|
|
|
1235
|
-
//
|
|
1236
|
-
|
|
1343
|
+
// The client-filtered set once `policy` has judged `contractNames`. A copy, so
|
|
1344
|
+
// older fetch state snapshots keep theirs: Utils.Set.add mutates in place.
|
|
1345
|
+
let switchToClientSideFiltering = (
|
|
1237
1346
|
clientFilteredContracts: Utils.Set.t<string>,
|
|
1238
|
-
~
|
|
1347
|
+
~contractNames: array<string>,
|
|
1348
|
+
~policy: clientFilterPolicy,
|
|
1349
|
+
~dynamicContracts: Utils.Set.t<string>,
|
|
1350
|
+
~addressStore: AddressStore.t,
|
|
1239
1351
|
~onNotice,
|
|
1240
|
-
~addressCount,
|
|
1241
|
-
~threshold,
|
|
1242
1352
|
// A resumed fetch state re-derives the switch from the persisted addresses,
|
|
1243
|
-
// but it already happened - and was reported - in
|
|
1244
|
-
// threshold.
|
|
1353
|
+
// but it already happened - and was reported - in an earlier run.
|
|
1245
1354
|
~isAlreadyReported=false,
|
|
1246
1355
|
) => {
|
|
1247
|
-
clientFilteredContracts->Utils.Set.
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1356
|
+
let switched = clientFilteredContracts->Utils.Set.toArray->Utils.Set.fromArray
|
|
1357
|
+
contractNames->Array.forEach(contractName =>
|
|
1358
|
+
if !(switched->Utils.Set.has(contractName)) {
|
|
1359
|
+
if policy.allDynamicContracts && dynamicContracts->Utils.Set.has(contractName) {
|
|
1360
|
+
switched->Utils.Set.add(contractName)->ignore
|
|
1361
|
+
} else {
|
|
1362
|
+
switch policy.addressThreshold {
|
|
1363
|
+
| Some(threshold) =>
|
|
1364
|
+
let addressCount = addressStore->AddressStore.contractCount(contractName)
|
|
1365
|
+
if addressCount > threshold {
|
|
1366
|
+
switched->Utils.Set.add(contractName)->ignore
|
|
1367
|
+
if !isAlreadyReported {
|
|
1368
|
+
onNotice(SwitchedToClientSideFiltering({contractName, addressCount, threshold}))
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
| None => ()
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
)
|
|
1376
|
+
switched
|
|
1251
1377
|
}
|
|
1252
1378
|
|
|
1253
1379
|
// The block a partition will have fetched to once everything on its pending
|
|
@@ -1723,6 +1849,54 @@ OptimizedPartitions.t => {
|
|
|
1723
1849
|
)
|
|
1724
1850
|
}
|
|
1725
1851
|
|
|
1852
|
+
let creationBlockKey = (~contractName, ~address: Address.t) =>
|
|
1853
|
+
`${contractName}:${address->Address.toString->String.toLowerCase}`
|
|
1854
|
+
|
|
1855
|
+
// Marks the response's events that were logged in the block their address was
|
|
1856
|
+
// registered in, once the registrations fetching has already passed are
|
|
1857
|
+
// dropped: those can't receive another item.
|
|
1858
|
+
let markCreationBlockEvents = (creationBlocks: dict<creationBlock>, ~newItems, ~fetchedThrough) => {
|
|
1859
|
+
creationBlocks
|
|
1860
|
+
->Dict.toArray
|
|
1861
|
+
->Array.forEach(((key, {block})) =>
|
|
1862
|
+
if block < fetchedThrough {
|
|
1863
|
+
creationBlocks->Utils.Dict.deleteInPlace(key)
|
|
1864
|
+
}
|
|
1865
|
+
)
|
|
1866
|
+
newItems->Array.forEach(item =>
|
|
1867
|
+
if item->Internal.getItemKind === 0 {
|
|
1868
|
+
let eventItem = item->Internal.castUnsafeEventItem
|
|
1869
|
+
let key = creationBlockKey(
|
|
1870
|
+
~contractName=eventItem.onEventRegistration.eventConfig.contractName,
|
|
1871
|
+
~address=eventItem.payload->Internal.getPayloadSrcAddress,
|
|
1872
|
+
)
|
|
1873
|
+
switch creationBlocks->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
1874
|
+
| Some({block, round}) if block === eventItem.blockNumber =>
|
|
1875
|
+
item->Internal.markItemCreationRound(round)
|
|
1876
|
+
| _ => ()
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
)
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
// The round a registration made by `item`'s handler belongs to: one past the
|
|
1883
|
+
// round `item` itself runs in, which is its address's registration round when
|
|
1884
|
+
// the event was logged in the block that address was registered in.
|
|
1885
|
+
let creationRoundOfRegistration = (fetchState: t, ~item: Internal.item) =>
|
|
1886
|
+
switch fetchState.creationBlocks {
|
|
1887
|
+
| None => 1
|
|
1888
|
+
| Some(creationBlocks) =>
|
|
1889
|
+
let eventItem = item->Internal.castUnsafeEventItem
|
|
1890
|
+
let key = creationBlockKey(
|
|
1891
|
+
~contractName=eventItem.onEventRegistration.eventConfig.contractName,
|
|
1892
|
+
~address=eventItem.payload->Internal.getPayloadSrcAddress,
|
|
1893
|
+
)
|
|
1894
|
+
switch creationBlocks->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
1895
|
+
| Some({block, round}) if block === eventItem.blockNumber => round + 1
|
|
1896
|
+
| _ => 1
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1726
1900
|
let registerDynamicContracts = (
|
|
1727
1901
|
fetchState: t,
|
|
1728
1902
|
~addressStore: AddressStore.t,
|
|
@@ -1761,6 +1935,17 @@ let registerDynamicContracts = (
|
|
|
1761
1935
|
let verdict = verdicts->Array.getUnsafe(idx)
|
|
1762
1936
|
switch verdict {
|
|
1763
1937
|
| Added({fetchable: true}) =>
|
|
1938
|
+
switch fetchState.creationBlocks {
|
|
1939
|
+
| Some(creationBlocks) =>
|
|
1940
|
+
creationBlocks->Dict.set(
|
|
1941
|
+
creationBlockKey(~contractName=registration.contractName, ~address=registration.address),
|
|
1942
|
+
{
|
|
1943
|
+
block: registration.registrationBlock,
|
|
1944
|
+
round: registration.creationRound->Option.getOr(1),
|
|
1945
|
+
},
|
|
1946
|
+
)
|
|
1947
|
+
| None => ()
|
|
1948
|
+
}
|
|
1764
1949
|
if !(registeringContractNames->Array.includes(registration.contractName)) {
|
|
1765
1950
|
registeringContractNames->Array.push(registration.contractName)->ignore
|
|
1766
1951
|
}
|
|
@@ -1862,34 +2047,16 @@ let registerDynamicContracts = (
|
|
|
1862
2047
|
}
|
|
1863
2048
|
}
|
|
1864
2049
|
|
|
1865
|
-
//
|
|
1866
|
-
//
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
->Utils.Set.toArray
|
|
1876
|
-
->Utils.Set.fromArray
|
|
1877
|
-
dynamicContractsRef.contents
|
|
1878
|
-
->Utils.Set.toArray
|
|
1879
|
-
->Array.forEach(contractName => {
|
|
1880
|
-
let addressCount = addressStore->AddressStore.contractCount(contractName)
|
|
1881
|
-
if !(clientFilteredContracts->Utils.Set.has(contractName)) && addressCount > threshold {
|
|
1882
|
-
clientFilteredContracts->addClientFilteredContract(
|
|
1883
|
-
~contractName,
|
|
1884
|
-
~onNotice,
|
|
1885
|
-
~addressCount,
|
|
1886
|
-
~threshold,
|
|
1887
|
-
)
|
|
1888
|
-
}
|
|
1889
|
-
})
|
|
1890
|
-
clientFilteredContracts
|
|
1891
|
-
| None => fetchState.optimizedPartitions.clientFilteredContracts
|
|
1892
|
-
}
|
|
2050
|
+
// Collapse in createPartitions folds a switched contract's partitions
|
|
2051
|
+
// into the single address-free partition.
|
|
2052
|
+
let clientFilteredContracts =
|
|
2053
|
+
fetchState.optimizedPartitions.clientFilteredContracts->switchToClientSideFiltering(
|
|
2054
|
+
~contractNames=dynamicContractsRef.contents->Utils.Set.toArray,
|
|
2055
|
+
~policy=fetchState.clientFilterPolicy,
|
|
2056
|
+
~dynamicContracts=dynamicContractsRef.contents,
|
|
2057
|
+
~addressStore,
|
|
2058
|
+
~onNotice,
|
|
2059
|
+
)
|
|
1893
2060
|
|
|
1894
2061
|
// Only this batch's additions need partitions; everything already
|
|
1895
2062
|
// registered has one.
|
|
@@ -1920,6 +2087,48 @@ let registerDynamicContracts = (
|
|
|
1920
2087
|
}
|
|
1921
2088
|
}
|
|
1922
2089
|
|
|
2090
|
+
// Every dynamic contract, the ones registered from now on included, is fetched
|
|
2091
|
+
// address-free and filtered on our side. Its partitions fold into the single
|
|
2092
|
+
// address-free partition through the same collapse the address threshold uses.
|
|
2093
|
+
let switchDynamicContractsToClientSideFiltering = (fetchState: t, ~addressStore: AddressStore.t) =>
|
|
2094
|
+
if fetchState.clientFilterPolicy.allDynamicContracts {
|
|
2095
|
+
fetchState
|
|
2096
|
+
} else {
|
|
2097
|
+
let fetchState = {
|
|
2098
|
+
...fetchState,
|
|
2099
|
+
clientFilterPolicy: {...fetchState.clientFilterPolicy, allDynamicContracts: true},
|
|
2100
|
+
}
|
|
2101
|
+
let {
|
|
2102
|
+
dynamicContracts,
|
|
2103
|
+
clientFilteredContracts,
|
|
2104
|
+
maxAddrInPartition,
|
|
2105
|
+
nextPartitionIndex,
|
|
2106
|
+
} = fetchState.optimizedPartitions
|
|
2107
|
+
let switched =
|
|
2108
|
+
clientFilteredContracts
|
|
2109
|
+
->Utils.Set.toArray
|
|
2110
|
+
->Array.concat(dynamicContracts->Utils.Set.toArray)
|
|
2111
|
+
->Utils.Set.fromArray
|
|
2112
|
+
if switched->Utils.Set.size === clientFilteredContracts->Utils.Set.size {
|
|
2113
|
+
fetchState
|
|
2114
|
+
} else {
|
|
2115
|
+
fetchState->updateInternal(
|
|
2116
|
+
~optimizedPartitions=createPartitions(
|
|
2117
|
+
~registeringSetsByContract=Dict.make(),
|
|
2118
|
+
~addressStore,
|
|
2119
|
+
~dynamicContracts,
|
|
2120
|
+
~clientFilteredContracts=switched,
|
|
2121
|
+
~normalSelection=fetchState.normalSelection,
|
|
2122
|
+
~maxAddrInPartition,
|
|
2123
|
+
~nextPartitionIndex,
|
|
2124
|
+
~existingPartitions=fetchState.optimizedPartitions.entities->Dict.valuesToArray,
|
|
2125
|
+
~progressBlockNumber=0,
|
|
2126
|
+
~knownHeight=fetchState.knownHeight,
|
|
2127
|
+
),
|
|
2128
|
+
)
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
|
|
1923
2132
|
/*
|
|
1924
2133
|
Updates fetchState with a response for a given query.
|
|
1925
2134
|
Throws if the partition with given query cannot be found (unexpected)
|
|
@@ -1941,12 +2150,80 @@ let handleQueryResult = (fetchState: t, ~query: query, ~latestFetchedBlock: int,
|
|
|
1941
2150
|
~mutItems=?{
|
|
1942
2151
|
switch newItems {
|
|
1943
2152
|
| [] => None
|
|
1944
|
-
| _ =>
|
|
2153
|
+
| _ =>
|
|
2154
|
+
switch fetchState.creationBlocks {
|
|
2155
|
+
| Some(creationBlocks) =>
|
|
2156
|
+
creationBlocks->markCreationBlockEvents(
|
|
2157
|
+
~newItems,
|
|
2158
|
+
~fetchedThrough=fetchState->bufferBlockNumber,
|
|
2159
|
+
)
|
|
2160
|
+
| None => ()
|
|
2161
|
+
}
|
|
2162
|
+
Some(fetchState.buffer->mergeIntoBuffer(newItems))
|
|
1945
2163
|
}
|
|
1946
2164
|
},
|
|
1947
2165
|
)
|
|
1948
2166
|
}
|
|
1949
2167
|
|
|
2168
|
+
// The items of the block handlers' register passes for the blocks after
|
|
2169
|
+
// `after`, through `through`, at most about `limit` of them in whole blocks;
|
|
2170
|
+
// and the last block they cover. `nextBlockRegisterItems` starts after the
|
|
2171
|
+
// last block passed.
|
|
2172
|
+
let capAtEndBlock = (fetchState: t, block) =>
|
|
2173
|
+
switch fetchState.endBlock {
|
|
2174
|
+
| Some(endBlock) => Pervasives.min(block, endBlock)
|
|
2175
|
+
| None => block
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
let canAdvanceBlockRegisters = (fetchState: t, ~through) =>
|
|
2179
|
+
switch fetchState.blockRegisterThrough {
|
|
2180
|
+
| Some(after) => fetchState->capAtEndBlock(through) > after
|
|
2181
|
+
| None => false
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
let blockRegisterItemsAfter = (fetchState: t, ~after, ~through, ~limit) =>
|
|
2185
|
+
switch fetchState.blockRegisterThrough {
|
|
2186
|
+
| Some(_) if fetchState->capAtEndBlock(through) > after =>
|
|
2187
|
+
let through = fetchState->capAtEndBlock(through)
|
|
2188
|
+
let items = []
|
|
2189
|
+
let covered = appendOnBlockItems(
|
|
2190
|
+
~mutItems=items,
|
|
2191
|
+
~onBlockRegistrations=fetchState.onBlockRegistrations->Array.filter((
|
|
2192
|
+
r: Internal.onBlockRegistration,
|
|
2193
|
+
) => r.contractRegister !== None),
|
|
2194
|
+
~indexerStartBlock=fetchState.startBlock,
|
|
2195
|
+
~fromBlock=after,
|
|
2196
|
+
~maxBlockNumber=through,
|
|
2197
|
+
~maxOnBlockBufferSize=limit,
|
|
2198
|
+
)
|
|
2199
|
+
Some((items, covered))
|
|
2200
|
+
| _ => None
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
let nextBlockRegisterItems = (fetchState: t, ~through, ~limit) =>
|
|
2204
|
+
switch fetchState.blockRegisterThrough {
|
|
2205
|
+
| Some(after) => fetchState->blockRegisterItemsAfter(~after, ~through, ~limit)
|
|
2206
|
+
| None => None
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
let setBlockRegisterThrough = (fetchState: t, ~through) =>
|
|
2210
|
+
switch fetchState.blockRegisterThrough {
|
|
2211
|
+
| Some(current) if through > current =>
|
|
2212
|
+
{...fetchState, blockRegisterThrough: through}->updateInternal
|
|
2213
|
+
| _ => fetchState
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
// How far block-handler register passes can run with no response to run them
|
|
2217
|
+
// with: through the block every partition has fetched, or the head when there
|
|
2218
|
+
// is no partition, and never past the chain's end block.
|
|
2219
|
+
let blockRegisterFrontier = (fetchState: t) =>
|
|
2220
|
+
fetchState->capAtEndBlock(
|
|
2221
|
+
switch fetchState.optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
|
|
2222
|
+
| Some(block) => Pervasives.min(block, fetchState.knownHeight)
|
|
2223
|
+
| None => fetchState.knownHeight
|
|
2224
|
+
},
|
|
2225
|
+
)
|
|
2226
|
+
|
|
1950
2227
|
type nextQuery =
|
|
1951
2228
|
| WaitingForNewBlock
|
|
1952
2229
|
| NothingToQuery
|
|
@@ -2387,6 +2664,20 @@ let acceptCandidates = (
|
|
|
2387
2664
|
}
|
|
2388
2665
|
}
|
|
2389
2666
|
|
|
2667
|
+
// A throttled chain lets `blockThrottle - 1` new blocks build up before it
|
|
2668
|
+
// fetches them, so a frontier that far behind the lagged head is waiting, not
|
|
2669
|
+
// behind. An end block the head has reached is fetched without waiting.
|
|
2670
|
+
let blocksBehindHeadAllowedByThrottle = ({blockThrottle, endBlock, knownHeight, blockLag}: t) =>
|
|
2671
|
+
switch endBlock {
|
|
2672
|
+
| Some(endBlock) if knownHeight - blockLag >= endBlock => 0
|
|
2673
|
+
| _ => Pervasives.max(0, blockThrottle - 1)
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
// The highest block the chain fetches up to right now: the lagged head, less the
|
|
2677
|
+
// blocks a throttled chain lets build up first.
|
|
2678
|
+
let headFetchTarget = ({knownHeight, blockLag} as fetchState: t) =>
|
|
2679
|
+
knownHeight - blockLag - fetchState->blocksBehindHeadAllowedByThrottle
|
|
2680
|
+
|
|
2390
2681
|
// Candidate queries are sized against chainTargetBlock, the soft querying
|
|
2391
2682
|
// horizon the owning chain wants to reach this tick — derived by ChainState
|
|
2392
2683
|
// from its share of the indexer-wide buffer budget and its chain-level event
|
|
@@ -2415,7 +2706,7 @@ let acceptCandidates = (
|
|
|
2415
2706
|
// rangeTargetDensity × (chainTargetBlock − fromBlock + 1) / inRangeCount — so
|
|
2416
2707
|
// unknown-density partitions probe in parallel within one budget.
|
|
2417
2708
|
let getNextQuery = (
|
|
2418
|
-
{optimizedPartitions, blockLag, latestOnBlockBlockNumber, knownHeight, endBlock}: t,
|
|
2709
|
+
{optimizedPartitions, blockLag, latestOnBlockBlockNumber, knownHeight, endBlock} as fetchState: t,
|
|
2419
2710
|
~chainTargetBlock: int,
|
|
2420
2711
|
~chainTargetItems: float,
|
|
2421
2712
|
) => {
|
|
@@ -2423,7 +2714,8 @@ let getNextQuery = (
|
|
|
2423
2714
|
if headBlockNumber <= 0 {
|
|
2424
2715
|
WaitingForNewBlock
|
|
2425
2716
|
} else {
|
|
2426
|
-
let
|
|
2717
|
+
let caughtUpBlockNumber = headBlockNumber - fetchState->blocksBehindHeadAllowedByThrottle
|
|
2718
|
+
let isOnBlockBehindTheHead = latestOnBlockBlockNumber < caughtUpBlockNumber
|
|
2427
2719
|
let shouldWaitForNewBlock = ref(
|
|
2428
2720
|
switch endBlock {
|
|
2429
2721
|
| Some(endBlock) => headBlockNumber < endBlock
|
|
@@ -2468,7 +2760,7 @@ let getNextQuery = (
|
|
|
2468
2760
|
}
|
|
2469
2761
|
}
|
|
2470
2762
|
inFlightCounts->Array.setUnsafe(idx, inFlightCount.contents)
|
|
2471
|
-
if p.mutPendingQueries->Array.length > 0 || p.latestFetchedBlock <
|
|
2763
|
+
if p.mutPendingQueries->Array.length > 0 || p.latestFetchedBlock < caughtUpBlockNumber {
|
|
2472
2764
|
// Even if there are some partitions waiting for the new block
|
|
2473
2765
|
// We still want to wait for all partitions reaching the head
|
|
2474
2766
|
// because they might update knownHeight in their response
|
|
@@ -2647,9 +2939,11 @@ let make = (
|
|
|
2647
2939
|
~progressBlockNumber=startBlock - 1,
|
|
2648
2940
|
~onBlockRegistrations=[],
|
|
2649
2941
|
~blockLag=0,
|
|
2942
|
+
~blockThrottle=0,
|
|
2650
2943
|
~firstEventBlock=None,
|
|
2651
2944
|
~clientFilterAddressThreshold=None,
|
|
2652
2945
|
~isResumed=false,
|
|
2946
|
+
~deferCreationBlockEvents=false,
|
|
2653
2947
|
): t => {
|
|
2654
2948
|
let latestFetchedBlock = progressBlockNumber
|
|
2655
2949
|
|
|
@@ -2729,7 +3023,6 @@ let make = (
|
|
|
2729
3023
|
})
|
|
2730
3024
|
|
|
2731
3025
|
let dynamicContracts = Utils.Set.make()
|
|
2732
|
-
let clientFilteredContracts = Utils.Set.make()
|
|
2733
3026
|
let registeringSetsByContract = Dict.make()
|
|
2734
3027
|
|
|
2735
3028
|
// What each contract needs a partition for is read back off the store rather
|
|
@@ -2753,26 +3046,24 @@ let make = (
|
|
|
2753
3046
|
}
|
|
2754
3047
|
})
|
|
2755
3048
|
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
switch clientFilterAddressThreshold {
|
|
2760
|
-
| Some(threshold) =>
|
|
2761
|
-
registeringSetsByContract->Utils.Dict.forEachWithKey((set, contractName) => {
|
|
2762
|
-
let addressCount = set->AddressSet.size
|
|
2763
|
-
if addressCount > threshold {
|
|
2764
|
-
clientFilteredContracts->addClientFilteredContract(
|
|
2765
|
-
~contractName,
|
|
2766
|
-
~onNotice,
|
|
2767
|
-
~addressCount,
|
|
2768
|
-
~threshold,
|
|
2769
|
-
~isAlreadyReported=isResumed,
|
|
2770
|
-
)
|
|
2771
|
-
}
|
|
2772
|
-
})
|
|
2773
|
-
| None => ()
|
|
3049
|
+
let clientFilterPolicy = {
|
|
3050
|
+
addressThreshold: clientFilterAddressThreshold,
|
|
3051
|
+
allDynamicContracts: false,
|
|
2774
3052
|
}
|
|
2775
3053
|
|
|
3054
|
+
// Switch at creation whatever the threshold already covers: a config
|
|
3055
|
+
// contract with a large static address list, or a dynamic contract restored
|
|
3056
|
+
// from a large persisted set.
|
|
3057
|
+
let clientFilteredContracts =
|
|
3058
|
+
Utils.Set.make()->switchToClientSideFiltering(
|
|
3059
|
+
~contractNames=registeringSetsByContract->Dict.keysToArray,
|
|
3060
|
+
~policy=clientFilterPolicy,
|
|
3061
|
+
~dynamicContracts,
|
|
3062
|
+
~addressStore,
|
|
3063
|
+
~onNotice,
|
|
3064
|
+
~isAlreadyReported=isResumed,
|
|
3065
|
+
)
|
|
3066
|
+
|
|
2776
3067
|
let optimizedPartitions = createPartitions(
|
|
2777
3068
|
~registeringSetsByContract,
|
|
2778
3069
|
~addressStore,
|
|
@@ -2805,6 +3096,14 @@ let make = (
|
|
|
2805
3096
|
// fetching, so without seeding the buffer here getNextQuery would return
|
|
2806
3097
|
// NothingToQuery and the indexer would get stuck.
|
|
2807
3098
|
let buffer = []
|
|
3099
|
+
// Every block up to the progress block was processed, so its register passes
|
|
3100
|
+
// ran and what they registered is in the seeded rows.
|
|
3101
|
+
let blockRegisterThrough =
|
|
3102
|
+
onBlockRegistrations->Array.some((r: Internal.onBlockRegistration) =>
|
|
3103
|
+
r.contractRegister !== None
|
|
3104
|
+
)
|
|
3105
|
+
? Some(progressBlockNumber)
|
|
3106
|
+
: None
|
|
2808
3107
|
let latestOnBlockBlockNumber = switch onBlockRegistrations {
|
|
2809
3108
|
// As updateInternal keeps it: with nothing to generate per block the pointer
|
|
2810
3109
|
// is the head cap on the buffer frontier, and left at the progress block it
|
|
@@ -2817,6 +3116,10 @@ let make = (
|
|
|
2817
3116
|
| None => knownHeight
|
|
2818
3117
|
| Some(latestFullyFetchedBlock) => Pervasives.min(latestFullyFetchedBlock, knownHeight)
|
|
2819
3118
|
}
|
|
3119
|
+
let maxBlockNumber = switch blockRegisterThrough {
|
|
3120
|
+
| Some(through) => Pervasives.min(maxBlockNumber, through)
|
|
3121
|
+
| None => maxBlockNumber
|
|
3122
|
+
}
|
|
2820
3123
|
appendOnBlockItems(
|
|
2821
3124
|
~mutItems=buffer,
|
|
2822
3125
|
~onBlockRegistrations,
|
|
@@ -2836,12 +3139,15 @@ let make = (
|
|
|
2836
3139
|
latestOnBlockBlockNumber,
|
|
2837
3140
|
normalSelection,
|
|
2838
3141
|
blockLag,
|
|
3142
|
+
blockThrottle,
|
|
2839
3143
|
onBlockRegistrations,
|
|
2840
3144
|
maxOnBlockBufferSize,
|
|
2841
3145
|
knownHeight,
|
|
2842
3146
|
buffer,
|
|
2843
3147
|
firstEventBlock,
|
|
2844
|
-
|
|
3148
|
+
clientFilterPolicy,
|
|
3149
|
+
creationBlocks: ?(deferCreationBlockEvents ? Some(Dict.make()) : None),
|
|
3150
|
+
?blockRegisterThrough,
|
|
2845
3151
|
}
|
|
2846
3152
|
|
|
2847
3153
|
fetchState
|
|
@@ -2993,6 +3299,13 @@ let rollback = (
|
|
|
2993
3299
|
fetchState.latestOnBlockBlockNumber,
|
|
2994
3300
|
targetBlockNumber,
|
|
2995
3301
|
),
|
|
3302
|
+
// The passes past the target run again on the refetched blocks: what they
|
|
3303
|
+
// registered was pruned from the store above.
|
|
3304
|
+
blockRegisterThrough: ?(
|
|
3305
|
+
fetchState.blockRegisterThrough->Option.map(through =>
|
|
3306
|
+
Pervasives.min(through, targetBlockNumber)
|
|
3307
|
+
)
|
|
3308
|
+
),
|
|
2996
3309
|
}->updateInternal(
|
|
2997
3310
|
~optimizedPartitions,
|
|
2998
3311
|
// Filtering the sorted buffer keeps it sorted and deduped.
|
|
@@ -3054,15 +3367,37 @@ let isActivelyIndexing = ({endBlock} as fetchState: t) => {
|
|
|
3054
3367
|
// True once the fetch frontier has reached the (lagged) head or endBlock,
|
|
3055
3368
|
// regardless of whether the buffer has been consumed yet. Unlike
|
|
3056
3369
|
// isReadyToEnterReorgThreshold, fetched-but-unprocessed items still count.
|
|
3057
|
-
let isFetchingAtHead = ({endBlock,
|
|
3370
|
+
let isFetchingAtHead = ({endBlock, knownHeight} as fetchState: t) => {
|
|
3058
3371
|
let bufferBlockNumber = fetchState->bufferBlockNumber
|
|
3059
3372
|
knownHeight !== 0 &&
|
|
3060
3373
|
switch endBlock {
|
|
3061
3374
|
| Some(endBlock) if bufferBlockNumber >= endBlock => true
|
|
3062
|
-
| _ => bufferBlockNumber >=
|
|
3375
|
+
| _ => bufferBlockNumber >= fetchState->headFetchTarget
|
|
3063
3376
|
}
|
|
3064
3377
|
}
|
|
3065
3378
|
|
|
3379
|
+
// Counted in blocks whatever the chain's block time: the chain still fetches
|
|
3380
|
+
// block by block near the head, and an address-free query must never reach back
|
|
3381
|
+
// into a range a partition is still backfilling.
|
|
3382
|
+
let headClientFilteringDistance = 200
|
|
3383
|
+
|
|
3384
|
+
// Every partition is within `headClientFilteringDistance` of the fetch target. A
|
|
3385
|
+
// chain with no head to follow never is: no known height yet, or an end block it
|
|
3386
|
+
// stops at before the head.
|
|
3387
|
+
let isWithinHeadClientFilteringDistance = (
|
|
3388
|
+
{endBlock, blockLag, knownHeight, optimizedPartitions} as fetchState: t,
|
|
3389
|
+
) =>
|
|
3390
|
+
knownHeight !== 0 &&
|
|
3391
|
+
switch endBlock {
|
|
3392
|
+
| Some(endBlock) => endBlock > knownHeight - blockLag
|
|
3393
|
+
| None => true
|
|
3394
|
+
} &&
|
|
3395
|
+
switch optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
|
|
3396
|
+
| Some(latestFetchedBlock) =>
|
|
3397
|
+
fetchState->headFetchTarget - latestFetchedBlock <= headClientFilteringDistance
|
|
3398
|
+
| None => true
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3066
3401
|
// Frontier at (or within `tolerance` of) the lagged head with no processable
|
|
3067
3402
|
// items left — the moment the chain can cross into the reorg threshold.
|
|
3068
3403
|
// `tolerance` absorbs the head advancing between a chain catching up and this
|