Skip to content

Commit

Permalink
Parse block tag in eth_call handler
Browse files Browse the repository at this point in the history
  • Loading branch information
prathamesh0 committed Sep 12, 2024
1 parent fb7e179 commit 7869b72
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 13 deletions.
5 changes: 3 additions & 2 deletions packages/cli/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ export class ServerCmd {
) => Promise<any>,
typeDefs: TypeSource,
paymentsManager?: PaymentsManager,
createEthRPCHandlers?: (indexer: IndexerInterface) => Promise<any>
createEthRPCHandlers?: (indexer: IndexerInterface, ethProvider: JsonRpcProvider) => Promise<any>
): Promise<{
app: Application,
server: ApolloServer
Expand All @@ -286,6 +286,7 @@ export class ServerCmd {
const jobQueue = this._baseCmd.jobQueue;
const indexer = this._baseCmd.indexer;
const eventWatcher = this._baseCmd.eventWatcher;
const ethProvider = this._baseCmd.ethProvider;

assert(config);
assert(jobQueue);
Expand Down Expand Up @@ -318,7 +319,7 @@ export class ServerCmd {
const gqlLogger = createGQLLogger(config.server.gql.logDir);
const resolvers = await createResolvers(indexer, eventWatcher, gqlLogger);

const ethRPCHandlers = createEthRPCHandlers ? await createEthRPCHandlers(indexer) : {};
const ethRPCHandlers = createEthRPCHandlers ? await createEthRPCHandlers(indexer, ethProvider) : {};

// Create an Express app
const app: Application = express();
Expand Down
53 changes: 42 additions & 11 deletions packages/util/src/eth-rpc-handlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { utils } from 'ethers';

import { JsonRpcProvider } from '@ethersproject/providers';

import { IndexerInterface } from './types';

const CODE_INVALID_PARAMS = -32602;
Expand All @@ -11,6 +15,7 @@ const ERROR_CONTRACT_INSUFFICIENT_PARAMS = 'Insufficient params';
const ERROR_CONTRACT_NOT_RECOGNIZED = 'Contract not recognized';
const ERROR_CONTRACT_METHOD_NOT_FOUND = 'Contract method not found';
const ERROR_METHOD_NOT_IMPLEMENTED = 'Method not implemented';
const ERROR_INVALID_BLOCK_TAG = 'Invalid block tag';

class ErrorWithCode extends Error {
code: number;
Expand All @@ -21,7 +26,8 @@ class ErrorWithCode extends Error {
}

export const createEthRPCHandlers = async (
indexer: IndexerInterface
indexer: IndexerInterface,
ethProvider: JsonRpcProvider
): Promise<any> => {
return {
eth_blockNumber: async (args: any, callback: any) => {
Expand All @@ -32,22 +38,18 @@ export const createEthRPCHandlers = async (
},

eth_call: async (args: any, callback: any) => {
// TODO: Parse blockTag

try {
if (!indexer.contractMap) {
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_MAP_NOT_SET);
}

if (args.length === 0) {
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_INSUFFICIENT_PARAMS);
}

const { to, data, blockTag } = args[0];

if (!indexer.contractMap) {
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_MAP_NOT_SET);
}

// For values other than blockHash, resolve value from block_progress table
const latestBlock = await indexer.getLatestCanonicalBlock();
const blockHash = latestBlock?.blockHash;
const blockHash = await parseBlockTag(indexer, ethProvider, blockTag);

const watchedContract = indexer.getWatchedContracts().find(contract => contract.address === to);
if (!watchedContract) {
Expand Down Expand Up @@ -78,7 +80,7 @@ export const createEthRPCHandlers = async (
}

const result = await indexerMethod(blockHash, to, ...decodedData);
const encodedResult = contractInterface.encodeFunctionResult(functionFragment, [result.value]);
const encodedResult = contractInterface.encodeFunctionResult(functionFragment, Array.isArray(result.value) ? result.value : [result.value]);

callback(null, encodedResult);
} catch (error: any) {
Expand All @@ -98,3 +100,32 @@ export const createEthRPCHandlers = async (
}
};
};

const parseBlockTag = async (indexer: IndexerInterface, ethProvider: JsonRpcProvider, blockTag: any): Promise<string> => {
if (utils.isHexString(blockTag)) {
// Return value if hex string is of block hash length
if (utils.hexDataLength(blockTag) === 32) {
return blockTag;
}

// Treat hex value as a block number
const block = await ethProvider.getBlock(blockTag);
return block.hash;
}

// TODO: Handle pending, safe and finalized
if (['earliest', 'latest', 'pending', 'safe', 'finalized', null, undefined].includes(blockTag)) {
const syncStatus = await indexer.getSyncStatus();
if (!syncStatus) {
throw new ErrorWithCode(CODE_INTERNAL_ERROR, 'SyncStatus not found');
}

if (blockTag === 'earliest') {
return syncStatus.initialIndexedBlockHash;
}

return syncStatus.latestIndexedBlockHash;
}

throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_INVALID_BLOCK_TAG);
};

0 comments on commit 7869b72

Please sign in to comment.