Add error handling to eth_call handler

This commit is contained in:
Prathamesh Musale 2024-09-12 16:24:05 +05:30
parent 8b70c22d17
commit fb7e1790d9

View File

@ -1,6 +1,25 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { IndexerInterface } from './types';
const CODE_INVALID_PARAMS = -32602;
const CODE_INTERNAL_ERROR = -32603;
const CODE_SERVER_ERROR = -32000;
const ERROR_CONTRACT_MAP_NOT_SET = 'Contract map not set';
const ERROR_CONTRACT_ABI_NOT_FOUND = 'Contract ABI not found';
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';
class ErrorWithCode extends Error {
code: number;
constructor (code: number, message: string) {
super(message);
this.code = code;
}
}
export const createEthRPCHandlers = async (
indexer: IndexerInterface
): Promise<any> => {
@ -13,48 +32,64 @@ export const createEthRPCHandlers = async (
},
eth_call: async (args: any, callback: any) => {
// TODO: Handle empty args
// TODO: Set errors in response
// TODO: Parse blockTag
const { to, data, blockTag } = args[0];
try {
if (args.length === 0) {
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_INSUFFICIENT_PARAMS);
}
// For values other than blockHash, resolve value from block_progress table
const latestBlock = await indexer.getLatestCanonicalBlock();
const blockHash = latestBlock?.blockHash;
const { to, data, blockTag } = args[0];
const watchedContract = indexer.getWatchedContracts().find(contract => contract.address === to);
if (!watchedContract) {
throw new Error('Contract not recognized');
}
if (!indexer.contractMap) {
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_MAP_NOT_SET);
}
if (!indexer.contractMap) {
throw new Error('Contract map not found');
}
// For values other than blockHash, resolve value from block_progress table
const latestBlock = await indexer.getLatestCanonicalBlock();
const blockHash = latestBlock?.blockHash;
const contractInterface = indexer.contractMap.get(watchedContract.kind);
if (!contractInterface) {
throw new Error('Contract ABI not found');
}
const watchedContract = indexer.getWatchedContracts().find(contract => contract.address === to);
if (!watchedContract) {
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_NOT_RECOGNIZED);
}
// Slice out method signature
const functionSelector = data.slice(0, 10);
const contractInterface = indexer.contractMap.get(watchedContract.kind);
if (!contractInterface) {
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_ABI_NOT_FOUND);
}
// Find the matching function from the ABI
const functionFragment = contractInterface.getFunction(functionSelector);
if (!functionFragment) {
throw new Error('Method not found');
}
// Slice out method signature from data
const functionSelector = data.slice(0, 10);
// Decode the data based on the matched function
const decodedData = contractInterface.decodeFunctionData(functionFragment, data);
// Find the matching function from the ABI
const functionFragment = contractInterface.getFunction(functionSelector);
if (!functionFragment) {
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_METHOD_NOT_FOUND);
}
// Decode the data based on the matched function
const decodedData = contractInterface.decodeFunctionData(functionFragment, data);
const functionName = functionFragment.name;
const indexerMethod = (indexer as any)[functionName].bind(indexer);
if (!indexerMethod) {
throw new ErrorWithCode(CODE_SERVER_ERROR, ERROR_METHOD_NOT_IMPLEMENTED);
}
const functionName = functionFragment.name;
const indexerMethod = (indexer as any)[functionName].bind(indexer);
if (indexerMethod && typeof indexerMethod === 'function') {
const result = await indexerMethod(blockHash, to, ...decodedData);
const encodedResult = contractInterface.encodeFunctionResult(functionFragment, [result.value]);
callback(null, encodedResult);
} catch (error: any) {
let callBackError;
if (error instanceof ErrorWithCode) {
callBackError = { code: error.code, message: error.message };
} else {
callBackError = { code: CODE_SERVER_ERROR, message: error.message };
}
callback(callBackError);
}
},