envio 3.8.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/index.d.ts +158 -104
- package/package.json +6 -6
- package/src/AddressRows.res +121 -0
- package/src/AddressRows.res.mjs +143 -0
- package/src/Batch.res +2 -0
- package/src/Batch.res.mjs +2 -1
- package/src/ChainState.res +76 -70
- package/src/ChainState.res.mjs +76 -65
- package/src/ChainState.resi +14 -9
- package/src/Config.res +23 -82
- package/src/Config.res.mjs +19 -63
- package/src/ContractMapping.res +66 -0
- package/src/ContractMapping.res.mjs +73 -0
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +4 -0
- package/src/EventConfigBuilder.res +0 -2
- package/src/EventConfigBuilder.res.mjs +0 -2
- package/src/FetchState.res +59 -67
- package/src/FetchState.res.mjs +34 -44
- package/src/InMemoryStore.res +17 -30
- package/src/InMemoryStore.res.mjs +11 -23
- package/src/IndexerState.res +21 -1
- package/src/IndexerState.res.mjs +9 -3
- package/src/IndexerState.resi +1 -0
- package/src/Main.res +25 -15
- package/src/Main.res.mjs +19 -14
- package/src/MemoryStorage.res +39 -66
- package/src/MemoryStorage.res.mjs +28 -65
- package/src/Metrics.res +15 -1
- package/src/Metrics.res.mjs +5 -1
- package/src/Persistence.res +30 -16
- package/src/Persistence.res.mjs +8 -5
- package/src/PgStorage.res +183 -65
- package/src/PgStorage.res.mjs +92 -58
- package/src/Rollback.res +14 -10
- package/src/Rollback.res.mjs +4 -2
- package/src/SimulateItems.res +5 -12
- package/src/SimulateItems.res.mjs +6 -10
- package/src/TestIndexer.res +93 -111
- package/src/TestIndexer.res.mjs +61 -88
- package/src/Utils.res +7 -0
- package/src/Utils.res.mjs +9 -2
- package/src/Writing.res +2 -0
- package/src/Writing.res.mjs +2 -1
- package/src/bindings/ClickHouse.res +6 -0
- package/src/bindings/ClickHouse.res.mjs +4 -0
- package/src/bindings/NodeJs.res +9 -0
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/bindings/Postgres.res +9 -0
- package/src/bindings/Postgres.res.mjs +3 -0
- package/src/db/EntityHistory.res +12 -18
- package/src/db/EntityHistory.res.mjs +3 -14
- package/src/db/InternalTable.res +171 -65
- package/src/db/InternalTable.res.mjs +176 -73
- package/src/db/Table.res +24 -0
- package/src/db/Table.res.mjs +20 -1
- package/src/sources/AddressSet.res +0 -22
- package/src/sources/AddressStore.res +48 -88
- package/src/sources/AddressStore.res.mjs +11 -22
- package/src/sources/SvmHyperSyncClient.res +17 -21
- package/src/sources/SvmHyperSyncSource.res +4 -9
- package/src/sources/SvmHyperSyncSource.res.mjs +5 -13
- package/svm.schema.json +10 -4
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Table from "./db/Table.res.mjs";
|
|
4
4
|
import * as Utils from "./Utils.res.mjs";
|
|
5
|
-
import * as Config from "./Config.res.mjs";
|
|
6
5
|
import * as Internal from "./Internal.res.mjs";
|
|
7
6
|
import * as ChainState from "./ChainState.res.mjs";
|
|
8
7
|
import * as EffectState from "./EffectState.res.mjs";
|
|
@@ -107,8 +106,8 @@ function dropCommittedEffects(inMemTable, committedCheckpointId, keepLoadedFromD
|
|
|
107
106
|
inMemTable.changesCount = inMemTable.changesCount - keysToDelete.length;
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
async function prepareRollbackDiff(state, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId) {
|
|
111
|
-
IndexerState.beginRollbackDiff(state, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId);
|
|
109
|
+
async function prepareRollbackDiff(state, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId, rolledBackAddresses) {
|
|
110
|
+
IndexerState.beginRollbackDiff(state, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId, rolledBackAddresses);
|
|
112
111
|
let persistence = IndexerState.persistence(state);
|
|
113
112
|
let committedCheckpointId = IndexerState.committedCheckpointId(state);
|
|
114
113
|
let deletedEntities = {};
|
|
@@ -142,8 +141,6 @@ async function prepareRollbackDiff(state, rollbackTargetCheckpointId, rollbackDi
|
|
|
142
141
|
}
|
|
143
142
|
|
|
144
143
|
function setBatchDcs(state, batch) {
|
|
145
|
-
let inMemTable = getInMemTable(state, Config.EnvioAddresses.entityConfig, "crossChain");
|
|
146
|
-
let committedCheckpointId = IndexerState.committedCheckpointId(state);
|
|
147
144
|
Utils.Dict.forEach(batch.progressedChainsById, progressedChain => {
|
|
148
145
|
let chainId = progressedChain.fetchState.chainId;
|
|
149
146
|
let chainState = IndexerState.getChainState(state, chainId);
|
|
@@ -158,24 +155,15 @@ function setBatchDcs(state, batch) {
|
|
|
158
155
|
checkpointBlockNumbers.push(batch.checkpointBlockNumbers[idx]);
|
|
159
156
|
}
|
|
160
157
|
}
|
|
161
|
-
ChainState.drainAddressesForWrite(chainState, progressedChain.progressBlockNumber, checkpointBlockNumbers).
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
contract_name: entity_contract_name
|
|
171
|
-
};
|
|
172
|
-
InMemoryTable.Entity.set(inMemTable, committedCheckpointId, {
|
|
173
|
-
type: "SET",
|
|
174
|
-
entityId: entity_id,
|
|
175
|
-
entity: entity,
|
|
176
|
-
checkpointId: checkpointIds[dc.checkpointIdx]
|
|
177
|
-
});
|
|
178
|
-
});
|
|
158
|
+
batch.registeredAddresses.push(...ChainState.drainAddressesForWrite(chainState, progressedChain.progressBlockNumber, checkpointBlockNumbers).map(dc => ({
|
|
159
|
+
row: {
|
|
160
|
+
chainId: chainId,
|
|
161
|
+
address: dc.address,
|
|
162
|
+
contractId: dc.contractId,
|
|
163
|
+
registrationBlock: dc.registrationBlock
|
|
164
|
+
},
|
|
165
|
+
checkpointId: checkpointIds[dc.checkpointIdx]
|
|
166
|
+
})));
|
|
179
167
|
});
|
|
180
168
|
}
|
|
181
169
|
|
package/src/IndexerState.res
CHANGED
|
@@ -267,6 +267,7 @@ let makeFromDbState = (
|
|
|
267
267
|
~isInReorgThreshold,
|
|
268
268
|
~isRealtime,
|
|
269
269
|
~config,
|
|
270
|
+
~contractMapping=initialState.contractMapping,
|
|
270
271
|
~registrationsByChainId,
|
|
271
272
|
~reducedPollingInterval?,
|
|
272
273
|
),
|
|
@@ -757,6 +758,7 @@ let drainBatchRun = (state: t): Batch.t => {
|
|
|
757
758
|
let checkpointBlockNumbers = []
|
|
758
759
|
let checkpointBlockHashes = []
|
|
759
760
|
let checkpointEventsProcessed = []
|
|
761
|
+
let registeredAddresses = []
|
|
760
762
|
all->Array.forEach(batch => {
|
|
761
763
|
// Once one batch lands in rest, all later ones follow it, preserving order.
|
|
762
764
|
if rest->Utils.Array.isEmpty && batch.isInReorgThreshold == isInReorgThreshold {
|
|
@@ -770,6 +772,7 @@ let drainBatchRun = (state: t): Batch.t => {
|
|
|
770
772
|
checkpointBlockNumbers->Array.pushMany(batch.checkpointBlockNumbers)
|
|
771
773
|
checkpointBlockHashes->Array.pushMany(batch.checkpointBlockHashes)
|
|
772
774
|
checkpointEventsProcessed->Array.pushMany(batch.checkpointEventsProcessed)
|
|
775
|
+
registeredAddresses->Array.pushMany(batch.registeredAddresses)
|
|
773
776
|
} else {
|
|
774
777
|
rest->Array.push(batch)
|
|
775
778
|
}
|
|
@@ -786,6 +789,7 @@ let drainBatchRun = (state: t): Batch.t => {
|
|
|
786
789
|
checkpointBlockNumbers,
|
|
787
790
|
checkpointBlockHashes,
|
|
788
791
|
checkpointEventsProcessed,
|
|
792
|
+
registeredAddresses,
|
|
789
793
|
}
|
|
790
794
|
}
|
|
791
795
|
|
|
@@ -797,7 +801,13 @@ let takeRollback = (state: t): option<Persistence.rollback> => {
|
|
|
797
801
|
}
|
|
798
802
|
|
|
799
803
|
// Advance the committed (durably persisted) frontier after a successful write.
|
|
800
|
-
|
|
804
|
+
// Written rows leave the buffer only once the transaction that holds them has
|
|
805
|
+
// committed. A failed write keeps them, and re-inserting a row the database
|
|
806
|
+
// already has is a no-op. Rows staged while the write was in flight belong to
|
|
807
|
+
// later checkpoints — ids only ever grow — so this can't drop one unwritten.
|
|
808
|
+
let markCommitted = (state: t, ~upToCheckpointId) => {
|
|
809
|
+
state.committedCheckpointId = upToCheckpointId
|
|
810
|
+
}
|
|
801
811
|
|
|
802
812
|
// Reset the in-memory tables and arm the rollback diff that the next write commits.
|
|
803
813
|
let beginRollbackDiff = (
|
|
@@ -805,15 +815,25 @@ let beginRollbackDiff = (
|
|
|
805
815
|
~targetCheckpointId,
|
|
806
816
|
~diffCheckpointId,
|
|
807
817
|
~progressBlockNumberByChainId,
|
|
818
|
+
~rolledBackAddresses,
|
|
808
819
|
) => {
|
|
809
820
|
let perChainEntities = state.allEntities->EntityTables.perChain
|
|
810
821
|
state.entities = EntityTables.make(state.allEntities->EntityTables.crossChain)
|
|
811
822
|
state->chainStates->Utils.Dict.forEach(cs => cs->ChainState.resetEntities(~perChainEntities))
|
|
812
823
|
state.effectState->EffectState.resetForRollback
|
|
824
|
+
// The address store reports only what each rollback killed, and never
|
|
825
|
+
// re-reports a registration it already tombstoned. A rollback that lands
|
|
826
|
+
// before the previous one has been written must therefore carry the earlier
|
|
827
|
+
// keys too, or their rows outlive every rollback that could delete them.
|
|
828
|
+
let rolledBackAddresses = switch state.rollback {
|
|
829
|
+
| Some({rolledBackAddresses: pending}) => pending->Array.concat(rolledBackAddresses)
|
|
830
|
+
| None => rolledBackAddresses
|
|
831
|
+
}
|
|
813
832
|
state.rollback = Some({
|
|
814
833
|
targetCheckpointId,
|
|
815
834
|
diffCheckpointId,
|
|
816
835
|
progressBlockNumberByChainId,
|
|
836
|
+
rolledBackAddresses,
|
|
817
837
|
})
|
|
818
838
|
}
|
|
819
839
|
|
package/src/IndexerState.res.mjs
CHANGED
|
@@ -100,7 +100,7 @@ function makeFromDbState(config, persistence, initialState, registrationsByChain
|
|
|
100
100
|
initialState.chains.forEach(resumedChainState => {
|
|
101
101
|
let chainId = Config.getChain(config, resumedChainState.id);
|
|
102
102
|
let chainConfig = ChainMap.get(config.chainMap, chainId);
|
|
103
|
-
chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval);
|
|
103
|
+
chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, initialState.contractMapping, registrationsByChainId, reducedPollingInterval);
|
|
104
104
|
});
|
|
105
105
|
let state = make(config, persistence, chainStates, isInReorgThreshold, isRealtime, targetBufferSize, initialState.checkpointId, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError, onExit);
|
|
106
106
|
CrossChainState.markCaughtUpOnResume(state.crossChainState);
|
|
@@ -625,6 +625,7 @@ function drainBatchRun(state) {
|
|
|
625
625
|
let checkpointBlockNumbers = [];
|
|
626
626
|
let checkpointBlockHashes = [];
|
|
627
627
|
let checkpointEventsProcessed = [];
|
|
628
|
+
let registeredAddresses = [];
|
|
628
629
|
all.forEach(batch => {
|
|
629
630
|
if (Utils.$$Array.isEmpty(rest) && batch.isInReorgThreshold === isInReorgThreshold) {
|
|
630
631
|
Utils.Dict.forEachWithKey(batch.progressedChainsById, (chainAfterBatch, key) => {
|
|
@@ -637,6 +638,7 @@ function drainBatchRun(state) {
|
|
|
637
638
|
checkpointBlockNumbers.push(...batch.checkpointBlockNumbers);
|
|
638
639
|
checkpointBlockHashes.push(...batch.checkpointBlockHashes);
|
|
639
640
|
checkpointEventsProcessed.push(...batch.checkpointEventsProcessed);
|
|
641
|
+
registeredAddresses.push(...batch.registeredAddresses);
|
|
640
642
|
} else {
|
|
641
643
|
rest.push(batch);
|
|
642
644
|
}
|
|
@@ -651,7 +653,8 @@ function drainBatchRun(state) {
|
|
|
651
653
|
checkpointChainIds: checkpointChainIds,
|
|
652
654
|
checkpointBlockNumbers: checkpointBlockNumbers,
|
|
653
655
|
checkpointBlockHashes: checkpointBlockHashes,
|
|
654
|
-
checkpointEventsProcessed: checkpointEventsProcessed
|
|
656
|
+
checkpointEventsProcessed: checkpointEventsProcessed,
|
|
657
|
+
registeredAddresses: registeredAddresses
|
|
655
658
|
};
|
|
656
659
|
}
|
|
657
660
|
|
|
@@ -665,14 +668,17 @@ function markCommitted(state, upToCheckpointId) {
|
|
|
665
668
|
state.committedCheckpointId = upToCheckpointId;
|
|
666
669
|
}
|
|
667
670
|
|
|
668
|
-
function beginRollbackDiff(state, targetCheckpointId, diffCheckpointId, progressBlockNumberByChainId) {
|
|
671
|
+
function beginRollbackDiff(state, targetCheckpointId, diffCheckpointId, progressBlockNumberByChainId, rolledBackAddresses) {
|
|
669
672
|
let perChainEntities = EntityTables.perChain(state.allEntities);
|
|
670
673
|
state.entities = EntityTables.make(EntityTables.crossChain(state.allEntities));
|
|
671
674
|
Utils.Dict.forEach(CrossChainState.chainStates(state.crossChainState), cs => ChainState.resetEntities(cs, perChainEntities));
|
|
672
675
|
EffectState.resetForRollback(state.effectState);
|
|
676
|
+
let match = state.rollback;
|
|
677
|
+
let rolledBackAddresses$1 = match !== undefined ? match.rolledBackAddresses.concat(rolledBackAddresses) : rolledBackAddresses;
|
|
673
678
|
state.rollback = {
|
|
674
679
|
targetCheckpointId: targetCheckpointId,
|
|
675
680
|
diffCheckpointId: diffCheckpointId,
|
|
681
|
+
rolledBackAddresses: rolledBackAddresses$1,
|
|
676
682
|
progressBlockNumberByChainId: progressBlockNumberByChainId
|
|
677
683
|
};
|
|
678
684
|
}
|
package/src/IndexerState.resi
CHANGED
|
@@ -143,6 +143,7 @@ let beginRollbackDiff: (
|
|
|
143
143
|
~targetCheckpointId: Internal.checkpointId,
|
|
144
144
|
~diffCheckpointId: Internal.checkpointId,
|
|
145
145
|
~progressBlockNumberByChainId: dict<int>,
|
|
146
|
+
~rolledBackAddresses: array<AddressRows.key>,
|
|
146
147
|
) => unit
|
|
147
148
|
let recordWriteFailure: (t, exn) => unit
|
|
148
149
|
let beginWriteFiber: (t, promise<unit>) => unit
|
package/src/Main.res
CHANGED
|
@@ -88,17 +88,22 @@ let getGlobalPersistence = () =>
|
|
|
88
88
|
let setGlobalPersistence = (persistence: Persistence.t) =>
|
|
89
89
|
EnvioGlobal.value.persistence = Some(persistence->(Utils.magic: Persistence.t => unknown))
|
|
90
90
|
|
|
91
|
-
let
|
|
91
|
+
let getInitialState = (): option<Persistence.initialState> => {
|
|
92
92
|
switch getGlobalPersistence() {
|
|
93
93
|
| Some(persistence) =>
|
|
94
94
|
switch persistence.storageStatus {
|
|
95
|
-
| Ready(initialState) => initialState
|
|
95
|
+
| Ready(initialState) => Some(initialState)
|
|
96
96
|
| _ => None
|
|
97
97
|
}
|
|
98
98
|
| None => None
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
let getInitialChainState = (~chainId: ChainId.t): option<Persistence.initialChainState> =>
|
|
103
|
+
getInitialState()->Option.flatMap(initialState =>
|
|
104
|
+
initialState.chains->Array.find(c => c.id === chainId)
|
|
105
|
+
)
|
|
106
|
+
|
|
102
107
|
// Importing `generated` must not trigger `Config.load()`,
|
|
103
108
|
// so the exported indexer calls this lazily on first `indexer.chains` access.
|
|
104
109
|
let buildChainsObject = (~config: Config.t) => {
|
|
@@ -184,20 +189,23 @@ let buildChainsObject = (~config: Config.t) => {
|
|
|
184
189
|
chainState->ChainState.contractAddresses(~contractName=contract.name)
|
|
185
190
|
}
|
|
186
191
|
// Before the global state is available (eg during handler
|
|
187
|
-
// module load after resume),
|
|
188
|
-
//
|
|
192
|
+
// module load after resume), read them off what persistence
|
|
193
|
+
// restored — which already holds the config's own addresses
|
|
194
|
+
// alongside the dynamically registered ones.
|
|
189
195
|
| None =>
|
|
190
|
-
switch
|
|
191
|
-
| Some(
|
|
192
|
-
|
|
193
|
-
chainState
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
196
|
+
switch getInitialState() {
|
|
197
|
+
| Some(initialState) =>
|
|
198
|
+
switch initialState.chains->Array.find(c => c.id === chainConfig.id) {
|
|
199
|
+
| Some(chainState) =>
|
|
200
|
+
chainState.addressRows->AddressRows.renderOfContract(
|
|
201
|
+
~ecosystem=(config.ecosystem.name :> string),
|
|
202
|
+
~shouldChecksum=!config.lowercaseAddresses,
|
|
203
|
+
~contractId=initialState.contractMapping->ContractMapping.idOfOrThrow(
|
|
204
|
+
contract.name,
|
|
205
|
+
),
|
|
206
|
+
)
|
|
207
|
+
| None => contract.addresses
|
|
208
|
+
}
|
|
201
209
|
| None => contract.addresses
|
|
202
210
|
}
|
|
203
211
|
}
|
|
@@ -577,6 +585,7 @@ let migrate = async (~reset) => {
|
|
|
577
585
|
await persistence->Persistence.init(
|
|
578
586
|
~reset,
|
|
579
587
|
~chainConfigs=config.chainMap->ChainMap.values,
|
|
588
|
+
~contractMapping=config.contractMapping,
|
|
580
589
|
~envioInfo=getEnvioInfo(),
|
|
581
590
|
~resetCommand="envio local db-migrate setup",
|
|
582
591
|
~runCommand=None,
|
|
@@ -628,6 +637,7 @@ let start = async (
|
|
|
628
637
|
await persistence->Persistence.init(
|
|
629
638
|
~reset,
|
|
630
639
|
~chainConfigs=config.chainMap->ChainMap.values,
|
|
640
|
+
~contractMapping=config.contractMapping,
|
|
631
641
|
~envioInfo=getEnvioInfo(),
|
|
632
642
|
~resetCommand=isDevelopmentMode ? "envio dev -r" : "envio start -r",
|
|
633
643
|
~runCommand=Some(isDevelopmentMode ? "envio dev" : "envio start"),
|
package/src/Main.res.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import * as Process from "process";
|
|
|
13
13
|
import * as ChainMap from "./ChainMap.res.mjs";
|
|
14
14
|
import * as PgStorage from "./PgStorage.res.mjs";
|
|
15
15
|
import * as ChainState from "./ChainState.res.mjs";
|
|
16
|
+
import * as AddressRows from "./AddressRows.res.mjs";
|
|
16
17
|
import * as EnvioGlobal from "./EnvioGlobal.res.mjs";
|
|
17
18
|
import * as IndexerLoop from "./IndexerLoop.res.mjs";
|
|
18
19
|
import * as Persistence from "./Persistence.res.mjs";
|
|
@@ -24,6 +25,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
24
25
|
import * as Helpers from "yargs/helpers";
|
|
25
26
|
import * as RollbackCommit from "./RollbackCommit.res.mjs";
|
|
26
27
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
28
|
+
import * as ContractMapping from "./ContractMapping.res.mjs";
|
|
27
29
|
import * as HandlerRegister from "./HandlerRegister.res.mjs";
|
|
28
30
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
29
31
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -94,7 +96,7 @@ function setGlobalPersistence(persistence) {
|
|
|
94
96
|
EnvioGlobal.value.persistence = Primitive_option.some(persistence);
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
function
|
|
99
|
+
function getInitialState() {
|
|
98
100
|
let persistence = EnvioGlobal.value.persistence;
|
|
99
101
|
if (persistence === undefined) {
|
|
100
102
|
return;
|
|
@@ -103,10 +105,14 @@ function getInitialChainState(chainId) {
|
|
|
103
105
|
if (typeof initialState !== "object" || initialState.TAG === "Initializing") {
|
|
104
106
|
return;
|
|
105
107
|
} else {
|
|
106
|
-
return initialState._0
|
|
108
|
+
return initialState._0;
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
function getInitialChainState(chainId) {
|
|
113
|
+
return Stdlib_Option.flatMap(getInitialState(), initialState => initialState.chains.find(c => c.id === chainId));
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
function buildChainsObject(config) {
|
|
111
117
|
let chainIds = [];
|
|
112
118
|
let chains = Object.create(null);
|
|
@@ -178,18 +184,16 @@ function buildChainsObject(config) {
|
|
|
178
184
|
let chainState = IndexerState.getChainState(Primitive_option.valFromOption(state), chainConfig.id);
|
|
179
185
|
return ChainState.contractAddresses(chainState, contract.name);
|
|
180
186
|
}
|
|
181
|
-
let
|
|
182
|
-
if (
|
|
187
|
+
let initialState = getInitialState();
|
|
188
|
+
if (initialState === undefined) {
|
|
189
|
+
return contract.addresses;
|
|
190
|
+
}
|
|
191
|
+
let chainState$1 = initialState.chains.find(c => c.id === chainConfig.id);
|
|
192
|
+
if (chainState$1 !== undefined) {
|
|
193
|
+
return AddressRows.renderOfContract(chainState$1.addressRows, config.ecosystem.name, !config.lowercaseAddresses, ContractMapping.idOfOrThrow(initialState.contractMapping, contract.name, undefined));
|
|
194
|
+
} else {
|
|
183
195
|
return contract.addresses;
|
|
184
196
|
}
|
|
185
|
-
let addresses = contract.addresses.slice();
|
|
186
|
-
chainState$1.indexingAddresses.forEach(dc => {
|
|
187
|
-
if (dc.contractName === contract.name) {
|
|
188
|
-
addresses.push(dc.address);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
return addresses;
|
|
193
197
|
}
|
|
194
198
|
});
|
|
195
199
|
Object.defineProperty(chainObj, contract.name, {
|
|
@@ -463,7 +467,7 @@ function getEnvioInfo() {
|
|
|
463
467
|
async function migrate(reset) {
|
|
464
468
|
let config = Config.load();
|
|
465
469
|
let persistence = PgStorage.makePersistenceFromConfig(config, undefined);
|
|
466
|
-
await Persistence.init(persistence, ChainMap.values(config.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), "envio local db-migrate setup", undefined, reset);
|
|
470
|
+
await Persistence.init(persistence, ChainMap.values(config.chainMap), config.contractMapping, Config.stripSensitiveData(Config.getPublicConfigJson()), "envio local db-migrate setup", undefined, reset);
|
|
467
471
|
return await persistence.storage.close();
|
|
468
472
|
}
|
|
469
473
|
|
|
@@ -490,7 +494,7 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
|
|
|
490
494
|
let isDevelopmentMode = !isTest && config.isDev;
|
|
491
495
|
let persistence$1 = persistence !== undefined ? persistence : PgStorage.makePersistenceFromConfig(config, undefined);
|
|
492
496
|
EnvioGlobal.value.persistence = Primitive_option.some(persistence$1);
|
|
493
|
-
await Persistence.init(persistence$1, ChainMap.values(config.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), isDevelopmentMode ? "envio dev -r" : "envio start -r", isDevelopmentMode ? "envio dev" : "envio start", reset);
|
|
497
|
+
await Persistence.init(persistence$1, ChainMap.values(config.chainMap), config.contractMapping, Config.stripSensitiveData(Config.getPublicConfigJson()), isDevelopmentMode ? "envio dev -r" : "envio start -r", isDevelopmentMode ? "envio dev" : "envio start", reset);
|
|
494
498
|
let registrationsByChainId = await HandlerLoader.registerAllHandlers(config);
|
|
495
499
|
let config$1;
|
|
496
500
|
if (isTest) {
|
|
@@ -552,6 +556,7 @@ export {
|
|
|
552
556
|
setIndexerState,
|
|
553
557
|
getGlobalPersistence,
|
|
554
558
|
setGlobalPersistence,
|
|
559
|
+
getInitialState,
|
|
555
560
|
getInitialChainState,
|
|
556
561
|
buildChainsObject,
|
|
557
562
|
getGlobalIndexer,
|
package/src/MemoryStorage.res
CHANGED
|
@@ -49,6 +49,7 @@ type t = {
|
|
|
49
49
|
cache: dict<Persistence.effectCacheRecord>,
|
|
50
50
|
effectCache: dict<dict<Internal.effectCacheItem>>,
|
|
51
51
|
mutable envioInfo: option<JSON.t>,
|
|
52
|
+
addresses: AddressRows.Table.t,
|
|
52
53
|
mutable isInitialized: bool,
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -61,6 +62,7 @@ let make = (): t => {
|
|
|
61
62
|
cache: Dict.make(),
|
|
62
63
|
effectCache: Dict.make(),
|
|
63
64
|
envioInfo: None,
|
|
65
|
+
addresses: AddressRows.Table.make(),
|
|
64
66
|
isInitialized: false,
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -117,61 +119,23 @@ let registerEntities = (state: t, ~entities: array<Internal.entityConfig>) =>
|
|
|
117
119
|
|
|
118
120
|
// Seeds the config's contract addresses, mirroring what PgStorage.initialize
|
|
119
121
|
// writes into `envio_addresses`.
|
|
120
|
-
let
|
|
121
|
-
|
|
122
|
-
chainConfigs
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
registrationLogIndex: -1,
|
|
132
|
-
}
|
|
133
|
-
dict->Dict.set(entity.id, entity->Config.EnvioAddresses.castToInternal)
|
|
134
|
-
},
|
|
135
|
-
)
|
|
136
|
-
)
|
|
137
|
-
)
|
|
122
|
+
let seedConfigAddresses = (
|
|
123
|
+
state: t,
|
|
124
|
+
~chainConfigs: array<Config.chain>,
|
|
125
|
+
~contractMapping,
|
|
126
|
+
~ecosystem,
|
|
127
|
+
) => {
|
|
128
|
+
// Initialize starts from an empty schema — the Postgres DDL drops and
|
|
129
|
+
// recreates one — so a re-initialize must not stack a second copy of the
|
|
130
|
+
// config's addresses on what a previous one left behind.
|
|
131
|
+
state.addresses->AddressRows.Table.clear
|
|
132
|
+
state.addresses->ChainState.seedConfigAddresses(~chainConfigs, ~ecosystem, ~contractMapping)
|
|
138
133
|
}
|
|
139
134
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingAddress => {
|
|
143
|
-
address: dc->Config.EnvioAddresses.getAddress,
|
|
144
|
-
contractName: dc.contractName,
|
|
145
|
-
registrationBlock: dc.registrationBlock,
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// All indexing addresses (config-seeded + dynamically registered) grouped by
|
|
149
|
-
// chain id string, derived from the envio_addresses entities.
|
|
150
|
-
let getIndexingAddressesByChain = (state: t): dict<array<Internal.indexingAddress>> => {
|
|
151
|
-
let byChain = Dict.make()
|
|
152
|
-
switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
|
|
153
|
-
| Some(dcDict) =>
|
|
154
|
-
dcDict
|
|
155
|
-
->Dict.valuesToArray
|
|
156
|
-
->Array.forEach(entity => {
|
|
157
|
-
let dc = entity->castToEnvioAddresses
|
|
158
|
-
let chainIdStr = dc.chainId->ChainId.toString
|
|
159
|
-
let contracts = switch byChain->Dict.get(chainIdStr) {
|
|
160
|
-
| Some(arr) => arr
|
|
161
|
-
| None =>
|
|
162
|
-
let arr = []
|
|
163
|
-
byChain->Dict.set(chainIdStr, arr)
|
|
164
|
-
arr
|
|
165
|
-
}
|
|
166
|
-
contracts->Array.push(dc->toIndexingAddress)->ignore
|
|
167
|
-
})
|
|
168
|
-
| None => ()
|
|
169
|
-
}
|
|
170
|
-
byChain
|
|
171
|
-
}
|
|
135
|
+
let addressRowsByChain = (state: t) => state.addresses->AddressRows.Table.groupByChain
|
|
172
136
|
|
|
173
137
|
let toInitialChainStates = (state: t): array<Persistence.initialChainState> => {
|
|
174
|
-
let addressesByChain = state->
|
|
138
|
+
let addressesByChain = state->addressRowsByChain
|
|
175
139
|
state.chains
|
|
176
140
|
->Dict.valuesToArray
|
|
177
141
|
->Array.map((chain): Persistence.initialChainState => {
|
|
@@ -183,9 +147,9 @@ let toInitialChainStates = (state: t): array<Persistence.initialChainState> => {
|
|
|
183
147
|
numEventsProcessed: chain.numEventsProcessed,
|
|
184
148
|
firstEventBlockNumber: chain.firstEventBlockNumber,
|
|
185
149
|
timestampCaughtUpToHeadOrEndblock: chain.timestampCaughtUpToHeadOrEndblock,
|
|
186
|
-
|
|
187
|
-
->Dict.
|
|
188
|
-
->Option.getOr(
|
|
150
|
+
addressRows: addressesByChain
|
|
151
|
+
->Utils.Dict.dangerouslyGetNonOption(chain.id->ChainId.toString)
|
|
152
|
+
->Option.getOr(AddressRows.emptySeedRows()),
|
|
189
153
|
sourceBlockNumber: chain.sourceBlockNumber,
|
|
190
154
|
})
|
|
191
155
|
}
|
|
@@ -220,13 +184,14 @@ let reorgCheckpoints = (state: t): array<Internal.reorgCheckpoint> =>
|
|
|
220
184
|
}
|
|
221
185
|
)
|
|
222
186
|
|
|
223
|
-
let toInitialState = (state: t, ~cleanRun): Persistence.initialState => {
|
|
187
|
+
let toInitialState = (state: t, ~cleanRun, ~contractMapping): Persistence.initialState => {
|
|
224
188
|
cleanRun,
|
|
189
|
+
contractMapping,
|
|
190
|
+
envioInfo: state.envioInfo,
|
|
225
191
|
cache: state.cache,
|
|
226
192
|
chains: state->toInitialChainStates,
|
|
227
193
|
checkpointId: state->committedCheckpointId,
|
|
228
194
|
reorgCheckpoints: state->reorgCheckpoints,
|
|
229
|
-
envioInfo: state.envioInfo,
|
|
230
195
|
}
|
|
231
196
|
|
|
232
197
|
let handleLoad = (state: t, ~tableName: string, ~filter: EntityFilter.t): array<
|
|
@@ -305,8 +270,10 @@ let backfillHistory = (
|
|
|
305
270
|
}
|
|
306
271
|
}
|
|
307
272
|
|
|
308
|
-
let applyRollback = (state: t, ~targetCheckpointId) => {
|
|
273
|
+
let applyRollback = (state: t, ~targetCheckpointId, ~rolledBackAddresses) => {
|
|
309
274
|
state.checkpoints = state.checkpoints->Array.filter(cp => cp.id <= targetCheckpointId)
|
|
275
|
+
// Addresses are removed by primary key, exactly like the Postgres delete.
|
|
276
|
+
rolledBackAddresses->Array.forEach(key => state.addresses->AddressRows.Table.delete(key))
|
|
310
277
|
state.history
|
|
311
278
|
->Dict.toArray
|
|
312
279
|
->Array.forEach(((name, rows)) =>
|
|
@@ -321,6 +288,7 @@ let writeBatch = (
|
|
|
321
288
|
~isInReorgThreshold,
|
|
322
289
|
~config: Config.t,
|
|
323
290
|
~updatedEntities: array<Persistence.updatedEntity>,
|
|
291
|
+
~registeredAddresses: array<AddressRows.staged>,
|
|
324
292
|
~updatedEffectsCache: array<Persistence.updatedEffectCache>,
|
|
325
293
|
~chainMetaData: option<dict<InternalTable.Chains.metaFields>>,
|
|
326
294
|
) => {
|
|
@@ -329,10 +297,13 @@ let writeBatch = (
|
|
|
329
297
|
// Rollback first, exactly like the Postgres transaction: the batch being
|
|
330
298
|
// written is the reprocessed one, so its rows must land on the reverted state.
|
|
331
299
|
switch rollback {
|
|
332
|
-
| Some({targetCheckpointId}) =>
|
|
300
|
+
| Some({targetCheckpointId, rolledBackAddresses}) =>
|
|
301
|
+
state->applyRollback(~targetCheckpointId, ~rolledBackAddresses)
|
|
333
302
|
| None => ()
|
|
334
303
|
}
|
|
335
304
|
|
|
305
|
+
registeredAddresses->Array.forEach(({row}) => state.addresses->AddressRows.Table.insert(row))
|
|
306
|
+
|
|
336
307
|
// The rollback diff restates what the reverted state already is, so it is not
|
|
337
308
|
// a change history should record — and an id it touches needs no backfill
|
|
338
309
|
// either, because the diff already carries its reverted value. Postgres draws
|
|
@@ -503,8 +474,7 @@ let getRollbackData = (
|
|
|
503
474
|
->ignore
|
|
504
475
|
| Some({action: DELETE, entityId, scope}) =>
|
|
505
476
|
removals->Array.push({Persistence.entityId, scope})->ignore
|
|
506
|
-
| Some({action: SET, entity: Some(entity)}) =>
|
|
507
|
-
restored->Array.push(entity)->ignore
|
|
477
|
+
| Some({action: SET, entity: Some(entity)}) => restored->Array.push(entity)->ignore
|
|
508
478
|
| Some({action: SET, entity: None}) => ()
|
|
509
479
|
}
|
|
510
480
|
})
|
|
@@ -553,9 +523,9 @@ let getRollbackProgressDiff = (state: t, ~rollbackTargetCheckpointId) => {
|
|
|
553
523
|
let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
554
524
|
name: "memory",
|
|
555
525
|
isInitialized: async () => state.isInitialized,
|
|
556
|
-
initialize: async (~chainConfigs=[], ~entities=[], ~enums as _=[], ~envioInfo) => {
|
|
526
|
+
initialize: async (~chainConfigs=[], ~entities=[], ~enums as _=[], ~contractMapping, ~envioInfo) => {
|
|
557
527
|
state->registerEntities(~entities)
|
|
558
|
-
state->
|
|
528
|
+
state->seedConfigAddresses(~chainConfigs, ~contractMapping, ~ecosystem=config.ecosystem.name)
|
|
559
529
|
chainConfigs->Array.forEach(chainConfig =>
|
|
560
530
|
state.chains->Dict.set(
|
|
561
531
|
chainConfig.id->ChainId.toString,
|
|
@@ -575,9 +545,10 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
575
545
|
)
|
|
576
546
|
state.envioInfo = Some(envioInfo)
|
|
577
547
|
state.isInitialized = true
|
|
578
|
-
state->toInitialState(~cleanRun=true)
|
|
548
|
+
state->toInitialState(~cleanRun=true, ~contractMapping)
|
|
579
549
|
},
|
|
580
|
-
resumeInitialState: async () =>
|
|
550
|
+
resumeInitialState: async () =>
|
|
551
|
+
state->toInitialState(~cleanRun=false, ~contractMapping=config.contractMapping),
|
|
581
552
|
loadOrThrow: async (~filter, ~table: Table.table) =>
|
|
582
553
|
state
|
|
583
554
|
->handleLoad(~tableName=table.tableName, ~filter)
|
|
@@ -594,14 +565,14 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
594
565
|
),
|
|
595
566
|
dumpEffectCache: async () => (),
|
|
596
567
|
reset: async () => {
|
|
597
|
-
let clear =
|
|
598
|
-
dict->Dict.keysToArray->Array.forEach(key => dict->Utils.Dict.deleteInPlace(key))
|
|
568
|
+
let clear = Utils.Dict.clearInPlace
|
|
599
569
|
state.entities->clear
|
|
600
570
|
state.history->clear
|
|
601
571
|
state.chains->clear
|
|
602
572
|
state.effectCache->clear
|
|
603
573
|
state.cache->clear
|
|
604
574
|
state.checkpoints = []
|
|
575
|
+
state.addresses->AddressRows.Table.clear
|
|
605
576
|
state.envioInfo = None
|
|
606
577
|
state.isInitialized = false
|
|
607
578
|
},
|
|
@@ -680,6 +651,7 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
680
651
|
~allEntities as _,
|
|
681
652
|
~updatedEffectsCache,
|
|
682
653
|
~updatedEntities,
|
|
654
|
+
~registeredAddresses,
|
|
683
655
|
~chainMetaData,
|
|
684
656
|
~onWrite as _,
|
|
685
657
|
) =>
|
|
@@ -689,6 +661,7 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
689
661
|
~isInReorgThreshold,
|
|
690
662
|
~config,
|
|
691
663
|
~updatedEntities,
|
|
664
|
+
~registeredAddresses,
|
|
692
665
|
~updatedEffectsCache,
|
|
693
666
|
~chainMetaData,
|
|
694
667
|
),
|