Regenerate ecliptic-watcher with latest changes in watcher-ts and run in active mode (#35)
* Regenerate ecliptic watcher * Update config data --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
8b236ed7ed
commit
ee0d059090
@ -81,7 +81,7 @@ To enable GQL requests caching:
|
|||||||
yarn server
|
yarn server
|
||||||
```
|
```
|
||||||
|
|
||||||
GQL console: http://localhost:3009/graphql
|
GQL console: http://localhost:3006/graphql
|
||||||
|
|
||||||
* If the watcher is an `active` watcher:
|
* If the watcher is an `active` watcher:
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ To enable GQL requests caching:
|
|||||||
yarn server
|
yarn server
|
||||||
```
|
```
|
||||||
|
|
||||||
GQL console: http://localhost:3009/graphql
|
GQL console: http://localhost:3006/graphql
|
||||||
|
|
||||||
* To watch a contract:
|
* To watch a contract:
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
[server]
|
[server]
|
||||||
host = "127.0.0.1"
|
host = "127.0.0.1"
|
||||||
port = 3006
|
port = 3006
|
||||||
kind = "lazy"
|
kind = "active"
|
||||||
|
gqlPath = "/graphql"
|
||||||
|
|
||||||
# Checkpointing state.
|
# Checkpointing state.
|
||||||
checkpointing = true
|
checkpointing = true
|
||||||
@ -11,15 +12,15 @@
|
|||||||
|
|
||||||
# Enable state creation
|
# Enable state creation
|
||||||
# CAUTION: Disable only if state creation is not desired or can be filled subsequently
|
# CAUTION: Disable only if state creation is not desired or can be filled subsequently
|
||||||
enableState = true
|
enableState = false
|
||||||
|
|
||||||
# Boolean to filter logs by contract.
|
|
||||||
filterLogs = false
|
|
||||||
|
|
||||||
# Max block range for which to return events in eventsInRange GQL query.
|
# Max block range for which to return events in eventsInRange GQL query.
|
||||||
# Use -1 for skipping check on block range.
|
# Use -1 for skipping check on block range.
|
||||||
maxEventsBlockRange = 1000
|
maxEventsBlockRange = 1000
|
||||||
|
|
||||||
|
# Flag to specify whether RPC endpoint supports block hash as block tag parameter
|
||||||
|
rpcSupportsBlockHashParam = false
|
||||||
|
|
||||||
# GQL cache settings
|
# GQL cache settings
|
||||||
[server.gqlCache]
|
[server.gqlCache]
|
||||||
enabled = true
|
enabled = true
|
||||||
@ -48,8 +49,19 @@
|
|||||||
|
|
||||||
[upstream]
|
[upstream]
|
||||||
[upstream.ethServer]
|
[upstream.ethServer]
|
||||||
gqlApiEndpoint = "http://127.0.0.1:8083/graphql"
|
gqlApiEndpoint = "http://127.0.0.1:8082/graphql"
|
||||||
rpcProviderEndpoint = "http://127.0.0.1:8082"
|
rpcProviderEndpoint = "http://127.0.0.1:8081"
|
||||||
|
|
||||||
|
# Boolean flag to specify if rpc-eth-client should be used for RPC endpoint instead of ipld-eth-client (ipld-eth-server GQL client)
|
||||||
|
rpcClient = true
|
||||||
|
|
||||||
|
# Boolean flag to specify if rpcProviderEndpoint is an FEVM RPC endpoint
|
||||||
|
isFEVM = false
|
||||||
|
|
||||||
|
# Boolean flag to filter event logs by contracts
|
||||||
|
filterLogsByAddresses = true
|
||||||
|
# Boolean flag to filter event logs by topics
|
||||||
|
filterLogsByTopics = false
|
||||||
|
|
||||||
[upstream.cache]
|
[upstream.cache]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
@ -61,6 +73,17 @@
|
|||||||
maxCompletionLagInSecs = 300
|
maxCompletionLagInSecs = 300
|
||||||
jobDelayInMilliSecs = 100
|
jobDelayInMilliSecs = 100
|
||||||
eventsInBatch = 50
|
eventsInBatch = 50
|
||||||
|
subgraphEventsOrder = true
|
||||||
blockDelayInMilliSecs = 2000
|
blockDelayInMilliSecs = 2000
|
||||||
prefetchBlocksInMem = true
|
|
||||||
prefetchBlockCount = 10
|
# Boolean to switch between modes of processing events when starting the server.
|
||||||
|
# Setting to true will fetch filtered events and required blocks in a range of blocks and then process them.
|
||||||
|
# Setting to false will fetch blocks consecutively with its events and then process them (Behaviour is followed in realtime processing near head).
|
||||||
|
useBlockRanges = true
|
||||||
|
|
||||||
|
# Block range in which logs are fetched during historical blocks processing
|
||||||
|
historicalLogsBlockRange = 2000
|
||||||
|
|
||||||
|
# Max block range of historical processing after which it waits for completion of events processing
|
||||||
|
# If set to -1 historical processing does not wait for events processing and completes till latest canonical block
|
||||||
|
historicalMaxFetchAhead = 10000
|
||||||
|
@ -38,28 +38,28 @@
|
|||||||
"homepage": "https://github.com/cerc-io/watcher-ts#readme",
|
"homepage": "https://github.com/cerc-io/watcher-ts#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.3.19",
|
"@apollo/client": "^3.3.19",
|
||||||
|
"@cerc-io/cli": "^0.2.74",
|
||||||
|
"@cerc-io/ipld-eth-client": "^0.2.74",
|
||||||
|
"@cerc-io/solidity-mapper": "^0.2.74",
|
||||||
|
"@cerc-io/util": "^0.2.74",
|
||||||
"@ethersproject/providers": "^5.4.4",
|
"@ethersproject/providers": "^5.4.4",
|
||||||
"@cerc-io/cli": "^0.2.40",
|
|
||||||
"@cerc-io/ipld-eth-client": "^0.2.40",
|
|
||||||
"@cerc-io/solidity-mapper": "^0.2.40",
|
|
||||||
"@cerc-io/util": "^0.2.40",
|
|
||||||
"apollo-type-bigint": "^0.1.3",
|
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
|
"decimal.js": "^10.3.1",
|
||||||
"ethers": "^5.4.4",
|
"ethers": "^5.4.4",
|
||||||
"graphql": "^15.5.0",
|
"graphql": "^15.5.0",
|
||||||
"json-bigint": "^1.0.0",
|
"json-bigint": "^1.0.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"typeorm": "^0.2.32",
|
"typeorm": "0.2.37",
|
||||||
"yargs": "^17.0.1",
|
"yargs": "^17.0.1"
|
||||||
"decimal.js": "^10.3.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ethersproject/abi": "^5.3.0",
|
"@ethersproject/abi": "^5.3.0",
|
||||||
"@types/yargs": "^17.0.0",
|
|
||||||
"@types/debug": "^4.1.5",
|
"@types/debug": "^4.1.5",
|
||||||
"@types/json-bigint": "^1.0.0",
|
"@types/json-bigint": "^1.0.0",
|
||||||
|
"@types/yargs": "^17.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.47.1",
|
"@typescript-eslint/eslint-plugin": "^5.47.1",
|
||||||
"@typescript-eslint/parser": "^5.47.1",
|
"@typescript-eslint/parser": "^5.47.1",
|
||||||
|
"copyfiles": "^2.4.1",
|
||||||
"eslint": "^8.35.0",
|
"eslint": "^8.35.0",
|
||||||
"eslint-config-semistandard": "^15.0.1",
|
"eslint-config-semistandard": "^15.0.1",
|
||||||
"eslint-config-standard": "^16.0.3",
|
"eslint-config-standard": "^16.0.3",
|
||||||
@ -69,7 +69,6 @@
|
|||||||
"eslint-plugin-standard": "^5.0.0",
|
"eslint-plugin-standard": "^5.0.0",
|
||||||
"husky": "^7.0.2",
|
"husky": "^7.0.2",
|
||||||
"ts-node": "^10.2.1",
|
"ts-node": "^10.2.1",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2"
|
||||||
"copyfiles": "^2.4.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,10 +350,10 @@ export class Database implements DatabaseInterface {
|
|||||||
return this._baseDatabase.saveBlockProgress(repo, block);
|
return this._baseDatabase.saveBlockProgress(repo, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveContract (queryRunner: QueryRunner, address: string, kind: string, checkpoint: boolean, startingBlock: number): Promise<Contract> {
|
async saveContract (queryRunner: QueryRunner, address: string, kind: string, checkpoint: boolean, startingBlock: number, context?: any): Promise<Contract> {
|
||||||
const repo = queryRunner.manager.getRepository(Contract);
|
const repo = queryRunner.manager.getRepository(Contract);
|
||||||
|
|
||||||
return this._baseDatabase.saveContract(repo, address, kind, checkpoint, startingBlock);
|
return this._baseDatabase.saveContract(repo, address, kind, checkpoint, startingBlock, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
async updateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
||||||
@ -374,6 +374,18 @@ export class Database implements DatabaseInterface {
|
|||||||
return this._baseDatabase.updateSyncStatusChainHead(repo, blockHash, blockNumber, force);
|
return this._baseDatabase.updateSyncStatusChainHead(repo, blockHash, blockNumber, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateSyncStatusProcessedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
||||||
|
const repo = queryRunner.manager.getRepository(SyncStatus);
|
||||||
|
|
||||||
|
return this._baseDatabase.updateSyncStatusProcessedBlock(repo, blockHash, blockNumber, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateSyncStatusIndexingError (queryRunner: QueryRunner, hasIndexingError: boolean): Promise<SyncStatus | undefined> {
|
||||||
|
const repo = queryRunner.manager.getRepository(SyncStatus);
|
||||||
|
|
||||||
|
return this._baseDatabase.updateSyncStatusIndexingError(repo, hasIndexingError);
|
||||||
|
}
|
||||||
|
|
||||||
async getSyncStatus (queryRunner: QueryRunner): Promise<SyncStatus | undefined> {
|
async getSyncStatus (queryRunner: QueryRunner): Promise<SyncStatus | undefined> {
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
const repo = queryRunner.manager.getRepository(SyncStatus);
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ export class BlockProgress implements BlockProgressInterface {
|
|||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id!: number;
|
id!: number;
|
||||||
|
|
||||||
@Column('varchar')
|
@Column('varchar', { nullable: true })
|
||||||
cid!: string;
|
cid!: string | null;
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
@Column('varchar', { length: 66 })
|
||||||
blockHash!: string;
|
blockHash!: string;
|
||||||
|
@ -21,4 +21,7 @@ export class Contract {
|
|||||||
|
|
||||||
@Column('integer')
|
@Column('integer')
|
||||||
startingBlock!: number;
|
startingBlock!: number;
|
||||||
|
|
||||||
|
@Column('jsonb', { nullable: true })
|
||||||
|
context!: Record<string, { data: any, type: number }>;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ export class StateSyncStatus {
|
|||||||
@Column('integer')
|
@Column('integer')
|
||||||
latestIndexedBlockNumber!: number;
|
latestIndexedBlockNumber!: number;
|
||||||
|
|
||||||
@Column('integer', { nullable: true })
|
@Column('integer')
|
||||||
latestCheckpointBlockNumber!: number;
|
latestCheckpointBlockNumber!: number;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,12 @@ export class SyncStatus implements SyncStatusInterface {
|
|||||||
@Column('integer')
|
@Column('integer')
|
||||||
latestIndexedBlockNumber!: number;
|
latestIndexedBlockNumber!: number;
|
||||||
|
|
||||||
|
@Column('varchar', { length: 66 })
|
||||||
|
latestProcessedBlockHash!: string;
|
||||||
|
|
||||||
|
@Column('integer')
|
||||||
|
latestProcessedBlockNumber!: number;
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
@Column('varchar', { length: 66 })
|
||||||
latestCanonicalBlockHash!: string;
|
latestCanonicalBlockHash!: string;
|
||||||
|
|
||||||
@ -33,4 +39,7 @@ export class SyncStatus implements SyncStatusInterface {
|
|||||||
|
|
||||||
@Column('integer')
|
@Column('integer')
|
||||||
initialIndexedBlockNumber!: number;
|
initialIndexedBlockNumber!: number;
|
||||||
|
|
||||||
|
@Column('boolean', { default: false })
|
||||||
|
hasIndexingError!: boolean;
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,9 @@ query getSyncStatus{
|
|||||||
latestIndexedBlockNumber
|
latestIndexedBlockNumber
|
||||||
latestCanonicalBlockHash
|
latestCanonicalBlockHash
|
||||||
latestCanonicalBlockNumber
|
latestCanonicalBlockNumber
|
||||||
|
initialIndexedBlockHash
|
||||||
|
initialIndexedBlockNumber
|
||||||
|
latestProcessedBlockHash
|
||||||
|
latestProcessedBlockNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,6 +14,6 @@ export const getApproved = fs.readFileSync(path.join(__dirname, 'getApproved.gql
|
|||||||
export const isApprovedForAll = fs.readFileSync(path.join(__dirname, 'isApprovedForAll.gql'), 'utf8');
|
export const isApprovedForAll = fs.readFileSync(path.join(__dirname, 'isApprovedForAll.gql'), 'utf8');
|
||||||
export const getSpawnLimit = fs.readFileSync(path.join(__dirname, 'getSpawnLimit.gql'), 'utf8');
|
export const getSpawnLimit = fs.readFileSync(path.join(__dirname, 'getSpawnLimit.gql'), 'utf8');
|
||||||
export const canEscapeTo = fs.readFileSync(path.join(__dirname, 'canEscapeTo.gql'), 'utf8');
|
export const canEscapeTo = fs.readFileSync(path.join(__dirname, 'canEscapeTo.gql'), 'utf8');
|
||||||
export const getSyncStatus = fs.readFileSync(path.join(__dirname, 'getSyncStatus.gql'), 'utf8');
|
|
||||||
export const getStateByCID = fs.readFileSync(path.join(__dirname, 'getStateByCID.gql'), 'utf8');
|
export const getStateByCID = fs.readFileSync(path.join(__dirname, 'getStateByCID.gql'), 'utf8');
|
||||||
export const getState = fs.readFileSync(path.join(__dirname, 'getState.gql'), 'utf8');
|
export const getState = fs.readFileSync(path.join(__dirname, 'getState.gql'), 'utf8');
|
||||||
|
export const getSyncStatus = fs.readFileSync(path.join(__dirname, 'getSyncStatus.gql'), 'utf8');
|
||||||
|
@ -6,11 +6,10 @@ import assert from 'assert';
|
|||||||
import { DeepPartial, FindConditions, FindManyOptions } from 'typeorm';
|
import { DeepPartial, FindConditions, FindManyOptions } from 'typeorm';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
import JSONbig from 'json-bigint';
|
import JSONbig from 'json-bigint';
|
||||||
import { ethers } from 'ethers';
|
import { ethers, constants } from 'ethers';
|
||||||
|
|
||||||
import { JsonFragment } from '@ethersproject/abi';
|
import { JsonFragment } from '@ethersproject/abi';
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
import { EthClient } from '@cerc-io/ipld-eth-client';
|
|
||||||
import { MappingKey, StorageLayout } from '@cerc-io/solidity-mapper';
|
import { MappingKey, StorageLayout } from '@cerc-io/solidity-mapper';
|
||||||
import {
|
import {
|
||||||
Indexer as BaseIndexer,
|
Indexer as BaseIndexer,
|
||||||
@ -25,7 +24,12 @@ import {
|
|||||||
ResultEvent,
|
ResultEvent,
|
||||||
getResultEvent,
|
getResultEvent,
|
||||||
DatabaseInterface,
|
DatabaseInterface,
|
||||||
Clients
|
Clients,
|
||||||
|
EthClient,
|
||||||
|
UpstreamConfig,
|
||||||
|
EthFullBlock,
|
||||||
|
EthFullTransaction,
|
||||||
|
ExtraEventData
|
||||||
} from '@cerc-io/util';
|
} from '@cerc-io/util';
|
||||||
|
|
||||||
import EclipticArtifacts from './artifacts/Ecliptic.json';
|
import EclipticArtifacts from './artifacts/Ecliptic.json';
|
||||||
@ -50,36 +54,60 @@ export class Indexer implements IndexerInterface {
|
|||||||
_ethProvider: BaseProvider;
|
_ethProvider: BaseProvider;
|
||||||
_baseIndexer: BaseIndexer;
|
_baseIndexer: BaseIndexer;
|
||||||
_serverConfig: ServerConfig;
|
_serverConfig: ServerConfig;
|
||||||
|
_upstreamConfig: UpstreamConfig;
|
||||||
|
|
||||||
_abiMap: Map<string, JsonFragment[]>;
|
_abiMap: Map<string, JsonFragment[]>;
|
||||||
_storageLayoutMap: Map<string, StorageLayout>;
|
_storageLayoutMap: Map<string, StorageLayout>;
|
||||||
_contractMap: Map<string, ethers.utils.Interface>;
|
_contractMap: Map<string, ethers.utils.Interface>;
|
||||||
|
eventSignaturesMap: Map<string, string[]>;
|
||||||
|
|
||||||
constructor (serverConfig: ServerConfig, db: DatabaseInterface, clients: Clients, ethProvider: BaseProvider, jobQueue: JobQueue) {
|
constructor (
|
||||||
|
config: {
|
||||||
|
server: ServerConfig;
|
||||||
|
upstream: UpstreamConfig;
|
||||||
|
},
|
||||||
|
db: DatabaseInterface,
|
||||||
|
clients: Clients,
|
||||||
|
ethProvider: BaseProvider,
|
||||||
|
jobQueue: JobQueue
|
||||||
|
) {
|
||||||
assert(db);
|
assert(db);
|
||||||
assert(clients.ethClient);
|
assert(clients.ethClient);
|
||||||
|
|
||||||
this._db = db as Database;
|
this._db = db as Database;
|
||||||
this._ethClient = clients.ethClient;
|
this._ethClient = clients.ethClient;
|
||||||
this._ethProvider = ethProvider;
|
this._ethProvider = ethProvider;
|
||||||
this._serverConfig = serverConfig;
|
this._serverConfig = config.server;
|
||||||
this._baseIndexer = new BaseIndexer(this._serverConfig, this._db, this._ethClient, this._ethProvider, jobQueue);
|
this._upstreamConfig = config.upstream;
|
||||||
|
this._baseIndexer = new BaseIndexer(config, this._db, this._ethClient, this._ethProvider, jobQueue);
|
||||||
|
|
||||||
this._abiMap = new Map();
|
this._abiMap = new Map();
|
||||||
this._storageLayoutMap = new Map();
|
this._storageLayoutMap = new Map();
|
||||||
this._contractMap = new Map();
|
this._contractMap = new Map();
|
||||||
|
this.eventSignaturesMap = new Map();
|
||||||
|
|
||||||
const { abi: EclipticABI } = EclipticArtifacts;
|
const { abi: EclipticABI } = EclipticArtifacts;
|
||||||
|
|
||||||
assert(EclipticABI);
|
assert(EclipticABI);
|
||||||
this._abiMap.set(KIND_ECLIPTIC, EclipticABI);
|
this._abiMap.set(KIND_ECLIPTIC, EclipticABI);
|
||||||
this._contractMap.set(KIND_ECLIPTIC, new ethers.utils.Interface(EclipticABI));
|
|
||||||
|
const EclipticContractInterface = new ethers.utils.Interface(EclipticABI);
|
||||||
|
this._contractMap.set(KIND_ECLIPTIC, EclipticContractInterface);
|
||||||
|
|
||||||
|
const EclipticEventSignatures = Object.values(EclipticContractInterface.events).map(value => {
|
||||||
|
return EclipticContractInterface.getEventTopic(value);
|
||||||
|
});
|
||||||
|
this.eventSignaturesMap.set(KIND_ECLIPTIC, EclipticEventSignatures);
|
||||||
}
|
}
|
||||||
|
|
||||||
get serverConfig (): ServerConfig {
|
get serverConfig (): ServerConfig {
|
||||||
return this._serverConfig;
|
return this._serverConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get upstreamConfig (): UpstreamConfig {
|
||||||
|
return this._upstreamConfig;
|
||||||
|
}
|
||||||
|
|
||||||
get storageLayoutMap (): Map<string, StorageLayout> {
|
get storageLayoutMap (): Map<string, StorageLayout> {
|
||||||
return this._storageLayoutMap;
|
return this._storageLayoutMap;
|
||||||
}
|
}
|
||||||
@ -536,16 +564,17 @@ export class Indexer implements IndexerInterface {
|
|||||||
await this._baseIndexer.removeStates(blockNumber, kind);
|
await this._baseIndexer.removeStates(blockNumber, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
async triggerIndexingOnEvent (event: Event): Promise<void> {
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
async triggerIndexingOnEvent (event: Event, extraData: ExtraEventData): Promise<void> {
|
||||||
const resultEvent = this.getResultEvent(event);
|
const resultEvent = this.getResultEvent(event);
|
||||||
|
|
||||||
// Call custom hook function for indexing on event.
|
// Call custom hook function for indexing on event.
|
||||||
await handleEvent(this, resultEvent);
|
await handleEvent(this, resultEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
async processEvent (event: Event): Promise<void> {
|
async processEvent (event: Event, extraData: ExtraEventData): Promise<void> {
|
||||||
// Trigger indexing of data based on the event.
|
// Trigger indexing of data based on the event.
|
||||||
await this.triggerIndexingOnEvent(event);
|
await this.triggerIndexingOnEvent(event, extraData);
|
||||||
}
|
}
|
||||||
|
|
||||||
async processBlock (blockProgress: BlockProgress): Promise<void> {
|
async processBlock (blockProgress: BlockProgress): Promise<void> {
|
||||||
@ -576,7 +605,11 @@ export class Indexer implements IndexerInterface {
|
|||||||
return this._db.getStateSyncStatus();
|
return this._db.getStateSyncStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateStateSyncStatusIndexedBlock (blockNumber: number, force?: boolean): Promise<StateSyncStatus> {
|
async updateStateSyncStatusIndexedBlock (blockNumber: number, force?: boolean): Promise<StateSyncStatus | undefined> {
|
||||||
|
if (!this._serverConfig.enableState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const dbTx = await this._db.createTransactionRunner();
|
const dbTx = await this._db.createTransactionRunner();
|
||||||
let res;
|
let res;
|
||||||
|
|
||||||
@ -610,10 +643,14 @@ export class Indexer implements IndexerInterface {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLatestCanonicalBlock (): Promise<BlockProgress> {
|
async getLatestCanonicalBlock (): Promise<BlockProgress | undefined> {
|
||||||
const syncStatus = await this.getSyncStatus();
|
const syncStatus = await this.getSyncStatus();
|
||||||
assert(syncStatus);
|
assert(syncStatus);
|
||||||
|
|
||||||
|
if (syncStatus.latestCanonicalBlockHash === constants.HashZero) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const latestCanonicalBlock = await this.getBlockProgress(syncStatus.latestCanonicalBlockHash);
|
const latestCanonicalBlock = await this.getBlockProgress(syncStatus.latestCanonicalBlockHash);
|
||||||
assert(latestCanonicalBlock);
|
assert(latestCanonicalBlock);
|
||||||
|
|
||||||
@ -624,8 +661,8 @@ export class Indexer implements IndexerInterface {
|
|||||||
return this._baseIndexer.getLatestStateIndexedBlock();
|
return this._baseIndexer.getLatestStateIndexedBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
async watchContract (address: string, kind: string, checkpoint: boolean, startingBlock: number): Promise<void> {
|
async watchContract (address: string, kind: string, checkpoint: boolean, startingBlock: number, context?: any): Promise<void> {
|
||||||
return this._baseIndexer.watchContract(address, kind, checkpoint, startingBlock);
|
return this._baseIndexer.watchContract(address, kind, checkpoint, startingBlock, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStateStatusMap (address: string, stateStatus: StateStatus): void {
|
updateStateStatusMap (address: string, stateStatus: StateStatus): void {
|
||||||
@ -640,6 +677,10 @@ export class Indexer implements IndexerInterface {
|
|||||||
return this._baseIndexer.saveEventEntity(dbEvent);
|
return this._baseIndexer.saveEventEntity(dbEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async saveEvents (dbEvents: Event[]): Promise<void> {
|
||||||
|
return this._baseIndexer.saveEvents(dbEvents);
|
||||||
|
}
|
||||||
|
|
||||||
async getEventsByFilter (blockHash: string, contract?: string, name?: string): Promise<Array<Event>> {
|
async getEventsByFilter (blockHash: string, contract?: string, name?: string): Promise<Array<Event>> {
|
||||||
return this._baseIndexer.getEventsByFilter(blockHash, contract, name);
|
return this._baseIndexer.getEventsByFilter(blockHash, contract, name);
|
||||||
}
|
}
|
||||||
@ -648,6 +689,10 @@ export class Indexer implements IndexerInterface {
|
|||||||
return this._baseIndexer.isWatchedContract(address);
|
return this._baseIndexer.isWatchedContract(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWatchedContracts (): Contract[] {
|
||||||
|
return this._baseIndexer.getWatchedContracts();
|
||||||
|
}
|
||||||
|
|
||||||
getContractsByKind (kind: string): Contract[] {
|
getContractsByKind (kind: string): Contract[] {
|
||||||
return this._baseIndexer.getContractsByKind(kind);
|
return this._baseIndexer.getContractsByKind(kind);
|
||||||
}
|
}
|
||||||
@ -682,6 +727,14 @@ export class Indexer implements IndexerInterface {
|
|||||||
return syncStatus;
|
return syncStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateSyncStatusProcessedBlock (blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
||||||
|
return this._baseIndexer.updateSyncStatusProcessedBlock(blockHash, blockNumber, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateSyncStatusIndexingError (hasIndexingError: boolean): Promise<SyncStatus | undefined> {
|
||||||
|
return this._baseIndexer.updateSyncStatusIndexingError(hasIndexingError);
|
||||||
|
}
|
||||||
|
|
||||||
async getEvent (id: string): Promise<Event | undefined> {
|
async getEvent (id: string): Promise<Event | undefined> {
|
||||||
return this._baseIndexer.getEvent(id);
|
return this._baseIndexer.getEvent(id);
|
||||||
}
|
}
|
||||||
@ -698,7 +751,24 @@ export class Indexer implements IndexerInterface {
|
|||||||
return this._baseIndexer.getBlocksAtHeight(height, isPruned);
|
return this._baseIndexer.getBlocksAtHeight(height, isPruned);
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveBlockAndFetchEvents (block: DeepPartial<BlockProgress>): Promise<[BlockProgress, DeepPartial<Event>[]]> {
|
async fetchAndSaveFilteredEventsAndBlocks (startBlock: number, endBlock: number): Promise<{
|
||||||
|
blockProgress: BlockProgress,
|
||||||
|
events: DeepPartial<Event>[],
|
||||||
|
ethFullBlock: EthFullBlock;
|
||||||
|
ethFullTransactions: EthFullTransaction[];
|
||||||
|
}[]> {
|
||||||
|
return this._baseIndexer.fetchAndSaveFilteredEventsAndBlocks(startBlock, endBlock, this.eventSignaturesMap, this.parseEventNameAndArgs.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchEventsForContracts (blockHash: string, blockNumber: number, addresses: string[]): Promise<DeepPartial<Event>[]> {
|
||||||
|
return this._baseIndexer.fetchEventsForContracts(blockHash, blockNumber, addresses, this.eventSignaturesMap, this.parseEventNameAndArgs.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveBlockAndFetchEvents (block: DeepPartial<BlockProgress>): Promise<[
|
||||||
|
BlockProgress,
|
||||||
|
DeepPartial<Event>[],
|
||||||
|
EthFullTransaction[]
|
||||||
|
]> {
|
||||||
return this._saveBlockAndFetchEvents(block);
|
return this._saveBlockAndFetchEvents(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,17 +797,26 @@ export class Indexer implements IndexerInterface {
|
|||||||
await this._baseIndexer.resetWatcherToBlock(blockNumber, entities);
|
await this._baseIndexer.resetWatcherToBlock(blockNumber, entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clearProcessedBlockData (block: BlockProgress): Promise<void> {
|
||||||
|
const entities = [...ENTITIES];
|
||||||
|
await this._baseIndexer.clearProcessedBlockData(block, entities);
|
||||||
|
}
|
||||||
|
|
||||||
async _saveBlockAndFetchEvents ({
|
async _saveBlockAndFetchEvents ({
|
||||||
cid: blockCid,
|
cid: blockCid,
|
||||||
blockHash,
|
blockHash,
|
||||||
blockNumber,
|
blockNumber,
|
||||||
blockTimestamp,
|
blockTimestamp,
|
||||||
parentHash
|
parentHash
|
||||||
}: DeepPartial<BlockProgress>): Promise<[BlockProgress, DeepPartial<Event>[]]> {
|
}: DeepPartial<BlockProgress>): Promise<[
|
||||||
|
BlockProgress,
|
||||||
|
DeepPartial<Event>[],
|
||||||
|
EthFullTransaction[]
|
||||||
|
]> {
|
||||||
assert(blockHash);
|
assert(blockHash);
|
||||||
assert(blockNumber);
|
assert(blockNumber);
|
||||||
|
|
||||||
const dbEvents = await this._baseIndexer.fetchEvents(blockHash, blockNumber, this.parseEventNameAndArgs.bind(this));
|
const { events: dbEvents, transactions } = await this._baseIndexer.fetchEvents(blockHash, blockNumber, this.eventSignaturesMap, this.parseEventNameAndArgs.bind(this));
|
||||||
|
|
||||||
const dbTx = await this._db.createTransactionRunner();
|
const dbTx = await this._db.createTransactionRunner();
|
||||||
try {
|
try {
|
||||||
@ -754,7 +833,7 @@ export class Indexer implements IndexerInterface {
|
|||||||
await dbTx.commitTransaction();
|
await dbTx.commitTransaction();
|
||||||
console.timeEnd(`time:indexer#_saveBlockAndFetchEvents-db-save-${blockNumber}`);
|
console.timeEnd(`time:indexer#_saveBlockAndFetchEvents-db-save-${blockNumber}`);
|
||||||
|
|
||||||
return [blockProgress, []];
|
return [blockProgress, [], transactions];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await dbTx.rollbackTransaction();
|
await dbTx.rollbackTransaction();
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -20,6 +20,7 @@ export const main = async (): Promise<any> => {
|
|||||||
|
|
||||||
await jobRunnerCmd.exec(async (jobRunner: JobRunner): Promise<void> => {
|
await jobRunnerCmd.exec(async (jobRunner: JobRunner): Promise<void> => {
|
||||||
await jobRunner.subscribeBlockProcessingQueue();
|
await jobRunner.subscribeBlockProcessingQueue();
|
||||||
|
await jobRunner.subscribeHistoricalProcessingQueue();
|
||||||
await jobRunner.subscribeEventProcessingQueue();
|
await jobRunner.subscribeEventProcessingQueue();
|
||||||
await jobRunner.subscribeBlockCheckpointQueue();
|
await jobRunner.subscribeBlockCheckpointQueue();
|
||||||
await jobRunner.subscribeHooksQueue();
|
await jobRunner.subscribeHooksQueue();
|
||||||
|
@ -3,13 +3,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import BigInt from 'apollo-type-bigint';
|
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
import Decimal from 'decimal.js';
|
import { GraphQLResolveInfo } from 'graphql';
|
||||||
import {
|
|
||||||
GraphQLScalarType,
|
|
||||||
GraphQLResolveInfo
|
|
||||||
} from 'graphql';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ValueResult,
|
ValueResult,
|
||||||
@ -17,6 +12,8 @@ import {
|
|||||||
gqlQueryCount,
|
gqlQueryCount,
|
||||||
getResultState,
|
getResultState,
|
||||||
IndexerInterface,
|
IndexerInterface,
|
||||||
|
GraphQLBigInt,
|
||||||
|
GraphQLBigDecimal,
|
||||||
EventWatcher,
|
EventWatcher,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
setGQLCacheHints
|
setGQLCacheHints
|
||||||
@ -33,20 +30,9 @@ export const createResolvers = async (indexerArg: IndexerInterface, eventWatcher
|
|||||||
const gqlCacheConfig = indexer.serverConfig.gqlCache;
|
const gqlCacheConfig = indexer.serverConfig.gqlCache;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
BigInt: new BigInt('bigInt'),
|
BigInt: GraphQLBigInt,
|
||||||
|
|
||||||
BigDecimal: new GraphQLScalarType({
|
BigDecimal: GraphQLBigDecimal,
|
||||||
name: 'BigDecimal',
|
|
||||||
description: 'BigDecimal custom scalar type',
|
|
||||||
parseValue (value) {
|
|
||||||
// value from the client
|
|
||||||
return new Decimal(value);
|
|
||||||
},
|
|
||||||
serialize (value: Decimal) {
|
|
||||||
// value sent to the client
|
|
||||||
return value.toFixed();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
Event: {
|
Event: {
|
||||||
__resolveType: (obj: any) => {
|
__resolveType: (obj: any) => {
|
||||||
@ -289,9 +275,14 @@ export const createResolvers = async (indexerArg: IndexerInterface, eventWatcher
|
|||||||
gqlTotalQueryCount.inc(1);
|
gqlTotalQueryCount.inc(1);
|
||||||
gqlQueryCount.labels('eventsInRange').inc(1);
|
gqlQueryCount.labels('eventsInRange').inc(1);
|
||||||
|
|
||||||
const { expected, actual } = await indexer.getProcessedBlockCountForRange(fromBlockNumber, toBlockNumber);
|
const syncStatus = await indexer.getSyncStatus();
|
||||||
if (expected !== actual) {
|
|
||||||
throw new Error(`Range not available, expected ${expected}, got ${actual} blocks in range`);
|
if (!syncStatus) {
|
||||||
|
throw new Error('No blocks processed yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fromBlockNumber < syncStatus.initialIndexedBlockNumber) || (toBlockNumber > syncStatus.latestProcessedBlockNumber)) {
|
||||||
|
throw new Error(`Block range should be between ${syncStatus.initialIndexedBlockNumber} and ${syncStatus.latestProcessedBlockNumber}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const events = await indexer.getEventsInRange(fromBlockNumber, toBlockNumber);
|
const events = await indexer.getEventsInRange(fromBlockNumber, toBlockNumber);
|
||||||
|
@ -16,7 +16,7 @@ type Proof {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type _Block_ {
|
type _Block_ {
|
||||||
cid: String!
|
cid: String
|
||||||
hash: String!
|
hash: String!
|
||||||
number: Int!
|
number: Int!
|
||||||
timestamp: Int!
|
timestamp: Int!
|
||||||
@ -87,13 +87,6 @@ type ResultBigInt {
|
|||||||
proof: Proof
|
proof: Proof
|
||||||
}
|
}
|
||||||
|
|
||||||
type SyncStatus {
|
|
||||||
latestIndexedBlockHash: String!
|
|
||||||
latestIndexedBlockNumber: Int!
|
|
||||||
latestCanonicalBlockHash: String!
|
|
||||||
latestCanonicalBlockNumber: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultState {
|
type ResultState {
|
||||||
block: _Block_!
|
block: _Block_!
|
||||||
contractAddress: String!
|
contractAddress: String!
|
||||||
@ -102,6 +95,17 @@ type ResultState {
|
|||||||
data: String!
|
data: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SyncStatus {
|
||||||
|
latestIndexedBlockHash: String!
|
||||||
|
latestIndexedBlockNumber: Int!
|
||||||
|
latestCanonicalBlockHash: String!
|
||||||
|
latestCanonicalBlockNumber: Int!
|
||||||
|
initialIndexedBlockHash: String!
|
||||||
|
initialIndexedBlockNumber: Int!
|
||||||
|
latestProcessedBlockHash: String!
|
||||||
|
latestProcessedBlockNumber: Int!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
events(blockHash: String!, contractAddress: String!, name: String): [ResultEvent!]
|
events(blockHash: String!, contractAddress: String!, name: String): [ResultEvent!]
|
||||||
eventsInRange(fromBlockNumber: Int!, toBlockNumber: Int!): [ResultEvent!]
|
eventsInRange(fromBlockNumber: Int!, toBlockNumber: Int!): [ResultEvent!]
|
||||||
@ -116,9 +120,9 @@ type Query {
|
|||||||
isApprovedForAll(blockHash: String!, contractAddress: String!, _owner: String!, _operator: String!): ResultBoolean!
|
isApprovedForAll(blockHash: String!, contractAddress: String!, _owner: String!, _operator: String!): ResultBoolean!
|
||||||
getSpawnLimit(blockHash: String!, contractAddress: String!, _point: BigInt!, _time: BigInt!): ResultBigInt!
|
getSpawnLimit(blockHash: String!, contractAddress: String!, _point: BigInt!, _time: BigInt!): ResultBigInt!
|
||||||
canEscapeTo(blockHash: String!, contractAddress: String!, _point: BigInt!, _sponsor: BigInt!): ResultBoolean!
|
canEscapeTo(blockHash: String!, contractAddress: String!, _point: BigInt!, _sponsor: BigInt!): ResultBoolean!
|
||||||
getSyncStatus: SyncStatus
|
|
||||||
getStateByCID(cid: String!): ResultState
|
getStateByCID(cid: String!): ResultState
|
||||||
getState(blockHash: String!, contractAddress: String!, kind: String): ResultState
|
getState(blockHash: String!, contractAddress: String!, kind: String): ResultState
|
||||||
|
getSyncStatus: SyncStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
|
Loading…
Reference in New Issue
Block a user