Handle template create events processing order during reorgs

This commit is contained in:
Nabarun 2024-08-05 16:02:37 +05:30 committed by Prathamesh Musale
parent a585500012
commit 74a85039e6
4 changed files with 51 additions and 14 deletions

View File

@ -635,6 +635,10 @@ export class Indexer implements IndexerInterface {
return this._baseIndexer.watchContract(address, kind, checkpoint, startingBlock, context);
}
async removeContract (address: string, kind: string): Promise<void> {
return this._baseIndexer.removeContract(address, kind);
}
updateStateStatusMap (address: string, stateStatus: StateStatus): void {
this._baseIndexer.updateStateStatusMap(address, stateStatus);
}

View File

@ -734,25 +734,13 @@ export const instantiate = async (
return __newString(dataSource.network);
},
'dataSource.create': async (name: number, params: number) => {
const [addressStringPtr] = __getArray(params);
const addressString = __getString(addressStringPtr);
const contractKind = __getString(name);
assert(indexer.watchContract);
assert(context.block);
await indexer.watchContract(utils.getAddress(addressString), contractKind, true, Number(context.block.blockNumber));
await handleDataSourceCreate(name, params);
},
'dataSource.createWithContext': async (name: number, params: number, dataSourceContext: number) => {
const [addressStringPtr] = __getArray(params);
const addressString = __getString(addressStringPtr);
const contractKind = __getString(name);
const contextInstance = await Entity.wrap(dataSourceContext);
const dbData = await database.fromGraphContext(instanceExports, contextInstance);
assert(indexer.watchContract);
assert(context.block);
await indexer.watchContract(utils.getAddress(addressString), contractKind, true, Number(context.block.blockNumber), dbData);
await handleDataSourceCreate(name, params, dbData);
}
},
json: {
@ -786,6 +774,34 @@ export const instantiate = async (
}
};
const handleDataSourceCreate = async (name: number, params: number, dbData?: {[key: string]: any}) => {
const [addressStringPtr] = __getArray(params);
const addressString = __getString(addressStringPtr);
const contractKind = __getString(name);
assert(context.block);
const contractAddress = utils.getAddress(addressString);
const watchedContracts = indexer.isContractAddressWatched(contractAddress);
// If template contract is already watched (incase of reorgs)
// Remove from watched contracts and throw error to reprocess block with correct order of template contract events
if (
watchedContracts &&
watchedContracts.some(watchedContract => watchedContract.kind === contractKind)
) {
await indexer.removeContract(contractAddress, contractKind);
throw new Error(`Template contract ${contractAddress} of kind ${contractKind} already exists; removed from watched contracts`);
}
await indexer.watchContract(
contractAddress,
contractKind,
true,
Number(context.block.blockNumber),
dbData
);
};
const instance = await loader.instantiate(source, imports);
const { exports: instanceExports } = instance;

View File

@ -920,6 +920,22 @@ export class Indexer {
}
}
async removeContract (address: string, kind: string): Promise<void> {
const dbTx = await this._db.createTransactionRunner();
try {
await this._db.deleteEntitiesByConditions(dbTx, 'contract', { kind, address });
this._clearWatchedContracts(
watchedContract => watchedContract.kind === kind && watchedContract.address === address
);
} catch (error) {
await dbTx.rollbackTransaction();
throw error;
} finally {
await dbTx.release();
}
}
cacheContract (contract: ContractInterface): void {
if (!this._watchedContractsByAddressMap[contract.address]) {
this._watchedContractsByAddressMap[contract.address] = [];

View File

@ -217,6 +217,7 @@ export interface IndexerInterface {
addContracts?: () => Promise<void>
cacheContract: (contract: ContractInterface) => void;
watchContract: (address: string, kind: string, checkpoint: boolean, startingBlock: number, context?: any) => Promise<void>
removeContract: (address: string, kind: string) => Promise<void>;
getEntityTypesMap?: () => Map<string, { [key: string]: string }>
getRelationsMap?: () => Map<any, { [key: string]: any }>
processInitialState: (contractAddress: string, blockHash: string) => Promise<any>