diff --git a/lerna.json b/lerna.json index 4e498425..f62fdf16 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "0.2.102", + "version": "0.2.103", "npmClient": "yarn", "useWorkspaces": true, "command": { diff --git a/packages/cache/package.json b/packages/cache/package.json index 96695147..c4e94f7d 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/cache", - "version": "0.2.102", + "version": "0.2.103", "description": "Generic object cache", "main": "dist/index.js", "scripts": { diff --git a/packages/cli/package.json b/packages/cli/package.json index d2fd8dc6..c9a21757 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/cli", - "version": "0.2.102", + "version": "0.2.103", "main": "dist/index.js", "license": "AGPL-3.0", "scripts": { @@ -15,13 +15,13 @@ }, "dependencies": { "@apollo/client": "^3.7.1", - "@cerc-io/cache": "^0.2.102", - "@cerc-io/ipld-eth-client": "^0.2.102", + "@cerc-io/cache": "^0.2.103", + "@cerc-io/ipld-eth-client": "^0.2.103", "@cerc-io/libp2p": "^0.42.2-laconic-0.1.4", "@cerc-io/nitro-node": "^0.1.15", - "@cerc-io/peer": "^0.2.102", - "@cerc-io/rpc-eth-client": "^0.2.102", - "@cerc-io/util": "^0.2.102", + "@cerc-io/peer": "^0.2.103", + "@cerc-io/rpc-eth-client": "^0.2.103", + "@cerc-io/util": "^0.2.103", "@ethersproject/providers": "^5.4.4", "@graphql-tools/utils": "^9.1.1", "@ipld/dag-cbor": "^8.0.0", diff --git a/packages/codegen/package.json b/packages/codegen/package.json index edd7370d..84fbdfc2 100644 --- a/packages/codegen/package.json +++ b/packages/codegen/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/codegen", - "version": "0.2.102", + "version": "0.2.103", "description": "Code generator", "private": true, "main": "index.js", @@ -20,7 +20,7 @@ }, "homepage": "https://github.com/cerc-io/watcher-ts#readme", "dependencies": { - "@cerc-io/util": "^0.2.102", + "@cerc-io/util": "^0.2.103", "@graphql-tools/load-files": "^6.5.2", "@npmcli/package-json": "^5.0.0", "@poanet/solidity-flattener": "https://github.com/vulcanize/solidity-flattener.git", diff --git a/packages/codegen/src/templates/indexer-template.handlebars b/packages/codegen/src/templates/indexer-template.handlebars index b8a308a5..11624ccc 100644 --- a/packages/codegen/src/templates/indexer-template.handlebars +++ b/packages/codegen/src/templates/indexer-template.handlebars @@ -249,7 +249,7 @@ export class Indexer implements IndexerInterface { }; } - const { block: { number } } = await this._ethClient.getBlockByHash(blockHash); + const { block: { number } } = await this.getBlockByHash(blockHash); const blockNumber = ethers.BigNumber.from(number).toNumber(); log('{{query.name}}: db miss, fetching from upstream server'); @@ -679,6 +679,10 @@ export class Indexer implements IndexerInterface { return this._baseIndexer.getBlocks(blockFilter); } + async getBlockByHash (blockHash?: string): Promise<{ block: any }> { + return this._baseIndexer.getBlockByHash(blockHash); + } + async updateSyncStatusIndexedBlock (blockHash: string, blockNumber: number, force = false): Promise { return this._baseIndexer.updateSyncStatusIndexedBlock(blockHash, blockNumber, force); } diff --git a/packages/codegen/src/templates/package-template.handlebars b/packages/codegen/src/templates/package-template.handlebars index d0cef973..4bec0da1 100644 --- a/packages/codegen/src/templates/package-template.handlebars +++ b/packages/codegen/src/templates/package-template.handlebars @@ -41,12 +41,12 @@ "homepage": "https://github.com/cerc-io/watcher-ts#readme", "dependencies": { "@apollo/client": "^3.3.19", - "@cerc-io/cli": "^0.2.102", - "@cerc-io/ipld-eth-client": "^0.2.102", - "@cerc-io/solidity-mapper": "^0.2.102", - "@cerc-io/util": "^0.2.102", + "@cerc-io/cli": "^0.2.103", + "@cerc-io/ipld-eth-client": "^0.2.103", + "@cerc-io/solidity-mapper": "^0.2.103", + "@cerc-io/util": "^0.2.103", {{#if (subgraphPath)}} - "@cerc-io/graph-node": "^0.2.102", + "@cerc-io/graph-node": "^0.2.103", {{/if}} "@ethersproject/providers": "^5.4.4", "debug": "^4.3.1", diff --git a/packages/graph-node/package.json b/packages/graph-node/package.json index 8e7dc8a7..148b2321 100644 --- a/packages/graph-node/package.json +++ b/packages/graph-node/package.json @@ -1,10 +1,10 @@ { "name": "@cerc-io/graph-node", - "version": "0.2.102", + "version": "0.2.103", "main": "dist/index.js", "license": "AGPL-3.0", "devDependencies": { - "@cerc-io/solidity-mapper": "^0.2.102", + "@cerc-io/solidity-mapper": "^0.2.103", "@ethersproject/providers": "^5.4.4", "@graphprotocol/graph-ts": "^0.22.0", "@nomiclabs/hardhat-ethers": "^2.0.2", @@ -51,9 +51,9 @@ "dependencies": { "@apollo/client": "^3.3.19", "@cerc-io/assemblyscript": "0.19.10-watcher-ts-0.1.2", - "@cerc-io/cache": "^0.2.102", - "@cerc-io/ipld-eth-client": "^0.2.102", - "@cerc-io/util": "^0.2.102", + "@cerc-io/cache": "^0.2.103", + "@cerc-io/ipld-eth-client": "^0.2.103", + "@cerc-io/util": "^0.2.103", "@types/json-diff": "^0.5.2", "@types/yargs": "^17.0.0", "bn.js": "^4.11.9", diff --git a/packages/graph-node/test/utils/indexer.ts b/packages/graph-node/test/utils/indexer.ts index 660aba1e..e31c3b56 100644 --- a/packages/graph-node/test/utils/indexer.ts +++ b/packages/graph-node/test/utils/indexer.ts @@ -95,6 +95,10 @@ export class Indexer implements IndexerInterface { return undefined; } + async getBlockByHash (blockHash?: string): Promise<{ block: any }> { + return { block: undefined }; + } + async getBlocksAtHeight (height: number, isPruned: boolean): Promise { assert(height); assert(isPruned); diff --git a/packages/ipld-eth-client/package.json b/packages/ipld-eth-client/package.json index 759aef69..93e57020 100644 --- a/packages/ipld-eth-client/package.json +++ b/packages/ipld-eth-client/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/ipld-eth-client", - "version": "0.2.102", + "version": "0.2.103", "description": "IPLD ETH Client", "main": "dist/index.js", "scripts": { @@ -20,8 +20,8 @@ "homepage": "https://github.com/cerc-io/watcher-ts#readme", "dependencies": { "@apollo/client": "^3.7.1", - "@cerc-io/cache": "^0.2.102", - "@cerc-io/util": "^0.2.102", + "@cerc-io/cache": "^0.2.103", + "@cerc-io/util": "^0.2.103", "cross-fetch": "^3.1.4", "debug": "^4.3.1", "ethers": "^5.4.4", diff --git a/packages/peer/package.json b/packages/peer/package.json index 30fda3c2..e29c9e10 100644 --- a/packages/peer/package.json +++ b/packages/peer/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/peer", - "version": "0.2.102", + "version": "0.2.103", "description": "libp2p module", "main": "dist/index.js", "exports": "./dist/index.js", diff --git a/packages/rpc-eth-client/package.json b/packages/rpc-eth-client/package.json index e4437ce2..0a0ad602 100644 --- a/packages/rpc-eth-client/package.json +++ b/packages/rpc-eth-client/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/rpc-eth-client", - "version": "0.2.102", + "version": "0.2.103", "description": "RPC ETH Client", "main": "dist/index.js", "scripts": { @@ -19,9 +19,9 @@ }, "homepage": "https://github.com/cerc-io/watcher-ts#readme", "dependencies": { - "@cerc-io/cache": "^0.2.102", - "@cerc-io/ipld-eth-client": "^0.2.102", - "@cerc-io/util": "^0.2.102", + "@cerc-io/cache": "^0.2.103", + "@cerc-io/ipld-eth-client": "^0.2.103", + "@cerc-io/util": "^0.2.103", "chai": "^4.3.4", "ethers": "^5.4.4", "left-pad": "^1.3.0", diff --git a/packages/solidity-mapper/package.json b/packages/solidity-mapper/package.json index 4e54fe2c..58dc191c 100644 --- a/packages/solidity-mapper/package.json +++ b/packages/solidity-mapper/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/solidity-mapper", - "version": "0.2.102", + "version": "0.2.103", "main": "dist/index.js", "license": "AGPL-3.0", "devDependencies": { diff --git a/packages/test/package.json b/packages/test/package.json index 5fe1b973..2ec2c705 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/test", - "version": "0.2.102", + "version": "0.2.103", "main": "dist/index.js", "license": "AGPL-3.0", "private": true, diff --git a/packages/tracing-client/package.json b/packages/tracing-client/package.json index 9df9cf14..f93f7c6f 100644 --- a/packages/tracing-client/package.json +++ b/packages/tracing-client/package.json @@ -1,6 +1,6 @@ { "name": "@cerc-io/tracing-client", - "version": "0.2.102", + "version": "0.2.103", "description": "ETH VM tracing client", "main": "dist/index.js", "scripts": { diff --git a/packages/util/package.json b/packages/util/package.json index 677032ed..2f69e784 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,13 +1,13 @@ { "name": "@cerc-io/util", - "version": "0.2.102", + "version": "0.2.103", "main": "dist/index.js", "license": "AGPL-3.0", "dependencies": { "@apollo/utils.keyvaluecache": "^1.0.1", "@cerc-io/nitro-node": "^0.1.15", - "@cerc-io/peer": "^0.2.102", - "@cerc-io/solidity-mapper": "^0.2.102", + "@cerc-io/peer": "^0.2.103", + "@cerc-io/solidity-mapper": "^0.2.103", "@cerc-io/ts-channel": "1.0.3-ts-nitro-0.1.1", "@ethersproject/properties": "^5.7.0", "@ethersproject/providers": "^5.4.4", @@ -54,7 +54,7 @@ "yargs": "^17.0.1" }, "devDependencies": { - "@cerc-io/cache": "^0.2.102", + "@cerc-io/cache": "^0.2.103", "@nomiclabs/hardhat-waffle": "^2.0.1", "@types/bunyan": "^1.8.8", "@types/express": "^4.17.14", diff --git a/packages/util/src/common.ts b/packages/util/src/common.ts index 049ff22a..f5eb1c9f 100644 --- a/packages/util/src/common.ts +++ b/packages/util/src/common.ts @@ -71,6 +71,22 @@ export const fetchBlocksAtHeight = async ( // Try fetching blocks from eth-server until found. while (!blocks.length) { + const { block: latestBlock } = await indexer.getBlockByHash(); + const blockProcessingOffset = jobQueueConfig.blockProcessingOffset ?? 0; + + // Process block if it is blockProcessingOffset blocks behind latest block + if (latestBlock.number < blockNumber + blockProcessingOffset) { + // Check number of retries for fetching new block + if (jobQueueConfig.maxNewBlockRetries && newBlockRetries > jobQueueConfig.maxNewBlockRetries) { + throw new Error(NEW_BLOCK_MAX_RETRIES_ERROR); + } + + newBlockRetries++; + log(`Latest block: ${latestBlock.number}, blockProcessingOffset: ${blockProcessingOffset}; retry block to process: ${blockNumber} after ${jobQueueConfig.blockDelayInMilliSecs}ms`); + await wait(jobQueueConfig.blockDelayInMilliSecs); + continue; + } + console.time(`time:common#_fetchBlocks-eth-server-${blockNumber}`); const ethFullBlocks = await indexer.getBlocks({ blockNumber }); console.timeEnd(`time:common#_fetchBlocks-eth-server-${blockNumber}`); @@ -84,32 +100,21 @@ export const fetchBlocksAtHeight = async ( // Fitler null blocks blocks = ethFullBlocks.filter(block => Boolean(block)) as EthFullBlock[]; - - if (!blocks.length) { - log(`No blocks fetched for block number ${blockNumber}, retrying after ${jobQueueConfig.blockDelayInMilliSecs} ms delay.`); - - // Check number of retries for fetching new block - if (jobQueueConfig.maxNewBlockRetries && newBlockRetries > jobQueueConfig.maxNewBlockRetries) { - throw new Error(NEW_BLOCK_MAX_RETRIES_ERROR); - } - - newBlockRetries++; - await wait(jobQueueConfig.blockDelayInMilliSecs); - } else { - blocks.forEach(block => { - blockAndEventsMap.set( - block.blockHash, - { - // Block is set later in job-runner when saving to database - block: {} as BlockProgressInterface, - events: [], - ethFullBlock: block, - // Transactions are set later in job-runner when fetching events - ethFullTransactions: [] - } - ); - }); - } + assert(blocks.length, `Blocks at ${blockNumber} should exist as latest block is ${latestBlock}`); + + blocks.forEach(block => { + blockAndEventsMap.set( + block.blockHash, + { + // Block is set later in job-runner when saving to database + block: {} as BlockProgressInterface, + events: [], + ethFullBlock: block, + // Transactions are set later in job-runner when fetching events + ethFullTransactions: [] + } + ); + }); } assert(blocks.length, 'Blocks not fetched'); diff --git a/packages/util/src/events.ts b/packages/util/src/events.ts index b6b2e5dc..ace4da5a 100644 --- a/packages/util/src/events.ts +++ b/packages/util/src/events.ts @@ -14,7 +14,6 @@ import { createPruningJob, processBlockByNumber } from './common'; import { OrderDirection } from './database'; import { HistoricalJobData, HistoricalJobResponseData } from './job-runner'; import { JobQueueConfig, ServerConfig } from './config'; -import { wait } from './misc'; const EVENT = 'event'; const BLOCK_PROGRESS_EVENT = 'block-progress-event'; @@ -105,7 +104,7 @@ export class EventWatcher { // Get latest block in chain and sync status from DB // Also get historical-processing queue size const [{ block: latestBlock }, syncStatus, historicalProcessingQueueSize] = await Promise.all([ - this._ethClient.getBlockByHash(), + this._indexer.getBlockByHash(), this._indexer.getSyncStatus(), this._jobQueue.getQueueSize(QUEUE_HISTORICAL_PROCESSING, 'completed') ]); @@ -196,18 +195,7 @@ export class EventWatcher { } if (isComplete) { - while (true) { - const { block: latestBlock } = await this._ethClient.getBlockByHash(); - - // Process block if it is blockProcessingOffset blocks behind latest block - if (latestBlock.number >= blockNumber + (this._config.jobQueue.blockProcessingOffset ?? 0)) { - await processBlockByNumber(this._jobQueue, blockNumber + 1); - break; - } - - log(`Latest block: ${latestBlock.number}; retry next block to process: ${blockNumber + 1} after ${this._config.jobQueue.blockDelayInMilliSecs}ms`); - await wait(this._config.jobQueue.blockDelayInMilliSecs); - } + await processBlockByNumber(this._jobQueue, blockNumber + 1); } } } diff --git a/packages/util/src/indexer.ts b/packages/util/src/indexer.ts index 395ba187..0fd0f0ba 100644 --- a/packages/util/src/indexer.ts +++ b/packages/util/src/indexer.ts @@ -394,6 +394,10 @@ export class Indexer { return blocks; } + async getBlockByHash (blockHash?: string): Promise<{ block: any }> { + return this._ethClient.getBlockByHash(blockHash); + } + async getBlockProgress (blockHash: string): Promise { return this._db.getBlockProgress(blockHash); } diff --git a/packages/util/src/metrics.ts b/packages/util/src/metrics.ts index 2a42b50e..6149352e 100644 --- a/packages/util/src/metrics.ts +++ b/packages/util/src/metrics.ts @@ -82,6 +82,12 @@ export const isSyncingHistoricalBlocks = new client.Gauge({ }); isSyncingHistoricalBlocks.set(Number(undefined)); +export const ethRpcCount = new client.Counter({ + name: 'watcher_eth_rpc_total', + help: 'Total number of ETH RPC requests', + labelNames: ['method', 'provider'] +}); + export const ethRpcErrors = new client.Counter({ name: 'watcher_eth_rpc_errors', help: 'Number of ETH RPC request errors', diff --git a/packages/util/src/misc.ts b/packages/util/src/misc.ts index 6d92c2a6..5477e085 100644 --- a/packages/util/src/misc.ts +++ b/packages/util/src/misc.ts @@ -22,7 +22,7 @@ import { ResultEvent } from './indexer'; import { EventInterface, EthFullBlock, EthFullTransaction } from './types'; import { BlockHeight } from './database'; import { Transaction } from './graph/utils'; -import { ethRpcErrors, ethRpcRequestDuration } from './metrics'; +import { ethRpcCount, ethRpcErrors, ethRpcRequestDuration } from './metrics'; const JSONbigNative = JSONbig({ useNativeBigInt: true }); @@ -379,6 +379,7 @@ export class MonitoredStaticJsonRpcProvider extends providers.StaticJsonRpcProvi // Rethrow the error throw err; } finally { + ethRpcCount.inc({ method, provider: this.connection.url }, 1); endTimer(); } } diff --git a/packages/util/src/types.ts b/packages/util/src/types.ts index 2d677a09..ee49108c 100644 --- a/packages/util/src/types.ts +++ b/packages/util/src/types.ts @@ -171,6 +171,7 @@ export interface IndexerInterface { getSyncStatus (): Promise getStateSyncStatus (): Promise getBlocks (blockFilter: { blockHash?: string, blockNumber?: number }): Promise> + getBlockByHash (blockHash?: string): Promise<{ block: any }> getBlocksAtHeight (height: number, isPruned: boolean): Promise getLatestCanonicalBlock (): Promise getLatestStateIndexedBlock (): Promise