diff --git a/packages/codegen/src/templates/config-template.handlebars b/packages/codegen/src/templates/config-template.handlebars index 4da4c89f..e365d016 100644 --- a/packages/codegen/src/templates/config-template.handlebars +++ b/packages/codegen/src/templates/config-template.handlebars @@ -28,6 +28,9 @@ # Enable ETH JSON RPC server at /rpc enableEthRPCServer = true + // Max number of logs that can be returned in a single getLogs request (default: 10000) + ethGetLogsResultLimit = 10000 + # Server GQL config [server.gql] path = "/graphql" diff --git a/packages/util/src/config.ts b/packages/util/src/config.ts index 9567a87a..62b3b096 100644 --- a/packages/util/src/config.ts +++ b/packages/util/src/config.ts @@ -255,6 +255,9 @@ export interface ServerConfig { // Enable ETH JSON RPC server at /rpc enableEthRPCServer: boolean; + + // Max number of logs that can be returned in a single getLogs request + ethGetLogsResultLimit?: number; } export interface FundingAmountsConfig { diff --git a/packages/util/src/constants.ts b/packages/util/src/constants.ts index 7c1fd66e..7bc135ae 100644 --- a/packages/util/src/constants.ts +++ b/packages/util/src/constants.ts @@ -30,3 +30,5 @@ export const DEFAULT_PREFETCH_BATCH_SIZE = 10; export const DEFAULT_MAX_GQL_CACHE_SIZE = Math.pow(2, 20) * 8; // 8 MB export const SUPPORTED_PAID_RPC_METHODS = ['eth_getBlockByHash', 'eth_getStorageAt', 'eth_getBlockByNumber']; + +export const DEFAULT_ETH_GET_LOGS_RESULT_LIMIT = 10000; diff --git a/packages/util/src/eth-rpc-handlers.ts b/packages/util/src/eth-rpc-handlers.ts index 03084977..7cfbb16a 100644 --- a/packages/util/src/eth-rpc-handlers.ts +++ b/packages/util/src/eth-rpc-handlers.ts @@ -1,10 +1,10 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ import { utils } from 'ethers'; import { Between, Equal, FindConditions, In, LessThanOrEqual, MoreThanOrEqual } from 'typeorm'; import { JsonRpcProvider } from '@ethersproject/providers'; import { EventInterface, IndexerInterface } from './types'; +import { DEFAULT_ETH_GET_LOGS_RESULT_LIMIT } from './constants'; const CODE_INVALID_PARAMS = -32602; const CODE_INTERNAL_ERROR = -32603; @@ -20,6 +20,7 @@ const ERROR_INVALID_BLOCK_TAG = 'Invalid block tag'; const ERROR_INVALID_BLOCK_HASH = 'Invalid block hash'; const ERROR_BLOCK_NOT_FOUND = 'Block not found'; const ERROR_TOPICS_FILTER_NOT_SUPPORTED = 'Topics filter not supported'; +const ERROR_LIMIT_EXCEEDED = 'Query results exceeds limit'; const DEFAULT_BLOCK_TAG = 'latest'; @@ -121,7 +122,9 @@ export const createEthRPCHandlers = async ( // Address filter, address or a list of addresses if (params.address) { if (Array.isArray(params.address)) { - where.contract = In(params.address); + if (params.address.length > 0) { + where.contract = In(params.address); + } } else { where.contract = Equal(params.address); } @@ -155,7 +158,13 @@ export const createEthRPCHandlers = async ( // Fetch events from the db // Load block relation - const events = await indexer.getEvents({ where, relations: ['block'] }); + const resultLimit = indexer.serverConfig.ethGetLogsResultLimit || DEFAULT_ETH_GET_LOGS_RESULT_LIMIT; + const events = await indexer.getEvents({ where, relations: ['block'], take: resultLimit + 1 }); + + // Limit number of results can be returned by a single query + if (events.length > resultLimit) { + throw new ErrorWithCode(CODE_SERVER_ERROR, `${ERROR_LIMIT_EXCEEDED}: ${resultLimit}`); + } // Transform events into result logs const result = await transformEventsToLogs(events);