From 237b4528da73523a3a590a662137c561ad569533 Mon Sep 17 00:00:00 2001 From: Ibrahim Bello <94493245+belloibrahv@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:57:25 +0100 Subject: [PATCH] Fix: Resolve Type Warnings for ConfigService.get() (#3350) * fix: resolve type warnings for ConfigService.get() - Ensured type consistency in all affected test cases. - Removed unnecessary type casting or added necessary casting. Signed-off-by: belloibrahv * fix: resolve type warnings for ConfigService.get() - Ensured type consistency in all affected test cases. - Removed unnecessary type casting or added necessary casting. Signed-off-by: belloibrahv * Refactor GlobalConfig and revert header changes as per feedback Signed-off-by: belloibrahv * Reverting License Header Changes Signed-off-by: belloibrahv * Refinment of ConfigService.get() (to conform to newly suggested changes) Signed-off-by: belloibrahv * Refactor ConfigService.get to enhance type safety and remove manual casting Signed-off-by: belloibrahv * fix bugs in workflow Signed-off-by: belloibrahv * Remove assesrtion Signed-off-by: belloibrahv * Remove assesrtion Signed-off-by: belloibrahv * Add assertion to _CONFIG (in the globalConfig.ts file) Signed-off-by: belloibrahv * chore: renamed types and added explanation Signed-off-by: Logan Nguyen * fix: loosen strict type checking for array types in config variables Signed-off-by: Logan Nguyen * fix: modified GetTypeOfConfigKey to resolve to better types Signed-off-by: Logan Nguyen * fix: updated properly default values to all global configs Signed-off-by: Logan Nguyen * fix: fixed ConfigService unit test Signed-off-by: Logan Nguyen * fix: fixed LocalLRUCache suite Signed-off-by: Logan Nguyen * fix: fixed HbarSpendingPlanConfigService suite Signed-off-by: Logan Nguyen * chore: updated type explanation Signed-off-by: Logan Nguyen Revert "chore: updated type explanation" This reverts commit ecd8d6eb0de5c292721bdd31696213a28a40d111. Reapply "chore: updated type explanation" This reverts commit 6756ecb1ee558c7d20fb8f7a71e2fbee70bb75ad. * fix: modified typeCasting to always convert CHAIN_ID to hexadecimal value Signed-off-by: Logan Nguyen * fix: further tighten ConfigService.get() Signed-off-by: Logan Nguyen * Update web3.ts Signed-off-by: Logan Nguyen * fix: fixed test in net Signed-off-by: Logan Nguyen * fix: fixed test in web3 Signed-off-by: Logan Nguyen * fix: fixed eth_feeHistory Signed-off-by: Logan Nguyen * fix: fixed filter API Signed-off-by: Logan Nguyen * fix: fixed HbarLimitService unit test Signed-off-by: Logan Nguyen Revert "fixed shouldLimit v1" This reverts commit 2f745e6f6188d7c4d84da931793544200420d073. Reapply "fixed shouldLimit v1" This reverts commit f280bbf311a4e407ed2c158d372581e2b8b36e25. s Signed-off-by: Logan Nguyen Revert "fix: fixed HbarLimitService unit test" This reverts commit ec28eee0f22911714095f9a9c3e69d42e286eb17. Reapply "fix: fixed HbarLimitService unit test" This reverts commit e27bae25cb51f5a49db525c5e66e08b3da2c3c15. Signed-off-by: Logan Nguyen * fix: fixed utils.spec.ts Signed-off-by: Logan Nguyen * fix: fixed BATCH_REQUESTS_ENABLED enabled by default Signed-off-by: Logan Nguyen * fix: fixed ws-server unit Signed-off-by: Logan Nguyen * chore: switch MULTI_SET to false Signed-off-by: Logan Nguyen * fix: fixed newHeads test Signed-off-by: Logan Nguyen * fix: removed type array in GlobalConfig Signed-off-by: Logan Nguyen * fix: reverted Copyright Signed-off-by: Logan Nguyen * chore: converted JSDoc to TSDoc Signed-off-by: Logan Nguyen * chore: replaced constant CACHE_MAX with config Signed-off-by: Logan Nguyen * chore: replaced constant CACHE_TTL.ONEHOUR with config 'CACHE_TTL' Signed-off-by: Logan Nguyen * chore: replaced constants.SEND_RAW_TRANSACTION_SIZE_LIMIT with config Signed-off-by: Logan Nguyen * chore: replaced constants. DEFAULT_ETH_GET_LOGS_BLOCK_RANGE_LIMIT with config value Signed-off-by: Logan Nguyen * chore: replaced constants.ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE with config Signed-off-by: Logan Nguyen * chore: replaced constants.MIRROR_NODE_RETRY_DELAY_DEFAULT with config Signed-off-by: Logan Nguyen * chore: replaced constants.MIRROR_NODE_REQUEST_RETRY_COUNT_DEFAULT with config Signed-off-by: Logan Nguyen * fix(ci): fixed ci test with fallback log level Signed-off-by: Logan Nguyen Revert "fix(ci): fixed ci test with fallback log level" This reverts commit 9af439697ccbb4424e3a3532be03c5a9860a5955. Reapply "fix(ci): fixed ci test with fallback log level" This reverts commit bd81c5729ffa7e4e20cf07cccbec718aff61af9b. Revert "fix(ci): fixed ci test with fallback log level" This reverts commit 981cad0a66a4e487d6e396dfcc0fa1123f19296f. Reapply "fix(ci): fixed ci test with fallback log level" This reverts commit 87eb44fd5fcd09156210cd431d7a0d00e9f8e720. * fix: alphabeticalized configuration tables Signed-off-by: Logan Nguyen --------- Signed-off-by: belloibrahv Signed-off-by: Logan Nguyen Co-authored-by: Logan Nguyen --- docs/configuration.md | 129 +- .../src/services/globalConfig.ts | 1517 +++++++++-------- packages/config-service/src/services/index.ts | 36 +- .../src/services/validationService.ts | 17 +- .../tests/src/services/configService.spec.ts | 71 +- .../tests/src/services/loggerService.spec.ts | 2 +- .../src/services/validationService.spec.ts | 8 +- .../src/lib/clients/cache/localLRUCache.ts | 7 +- .../relay/src/lib/clients/cache/redisCache.ts | 6 +- .../relay/src/lib/clients/mirrorNodeClient.ts | 64 +- packages/relay/src/lib/clients/sdkClient.ts | 15 +- .../config/hbarSpendingPlanConfigService.ts | 2 +- packages/relay/src/lib/constants.ts | 36 +- packages/relay/src/lib/eth.ts | 21 +- packages/relay/src/lib/net.ts | 6 +- packages/relay/src/lib/poller.ts | 5 +- packages/relay/src/lib/precheck.ts | 3 +- packages/relay/src/lib/relay.ts | 10 +- .../lib/services/cacheService/cacheService.ts | 3 - .../ethService/ethCommonService/index.ts | 2 +- .../lib/services/hapiService/hapiService.ts | 17 +- .../relay/src/lib/subscriptionController.ts | 19 +- packages/relay/src/lib/web3.ts | 2 +- packages/relay/src/utils.ts | 7 +- packages/relay/tests/helpers.ts | 3 +- .../tests/lib/clients/localLRUCache.spec.ts | 2 +- .../hbarSpendingPlanConfigService.spec.ts | 6 +- packages/relay/tests/lib/eth/eth-config.ts | 7 +- packages/relay/tests/lib/eth/eth-helpers.ts | 2 +- .../relay/tests/lib/eth/eth_common.spec.ts | 3 +- .../tests/lib/eth/eth_feeHistory.spec.ts | 1 + .../lib/eth/eth_sendRawTransaction.spec.ts | 4 +- .../relay/tests/lib/ethGetBlockBy.spec.ts | 2 +- packages/relay/tests/lib/hapiService.spec.ts | 2 +- .../relay/tests/lib/mirrorNodeClient.spec.ts | 16 +- packages/relay/tests/lib/net.spec.ts | 29 +- packages/relay/tests/lib/openrpc.spec.ts | 2 +- packages/relay/tests/lib/poller.spec.ts | 11 +- packages/relay/tests/lib/sdkClient.spec.ts | 8 +- .../tests/lib/services/eth/filter.spec.ts | 2 +- .../hbarLimitService/hbarLimitService.spec.ts | 17 +- .../metricService/metricService.spec.ts | 8 +- packages/relay/tests/lib/utils.spec.ts | 29 +- packages/relay/tests/lib/web3.spec.ts | 7 +- packages/server/src/index.ts | 2 +- .../src/koaJsonRpc/lib/methodConfiguration.ts | 16 +- packages/server/src/koaJsonRpc/lib/utils.ts | 17 +- packages/server/src/server.ts | 19 +- .../tests/acceptance/conformityTests.spec.ts | 4 +- .../tests/acceptance/hbarLimiter.spec.ts | 16 +- .../server/tests/acceptance/index.spec.ts | 19 +- .../tests/acceptance/rateLimiter.spec.ts | 12 +- .../tests/acceptance/rpc_batch1.spec.ts | 19 +- .../tests/acceptance/rpc_batch2.spec.ts | 2 +- .../tests/acceptance/rpc_batch3.spec.ts | 10 +- .../tests/acceptance/serverConfig.spec.ts | 7 +- packages/server/tests/helpers/assertions.ts | 2 +- .../server/tests/integration/server.spec.ts | 59 +- .../src/metrics/connectionLimiter.ts | 21 +- packages/ws-server/src/utils/utils.ts | 8 +- packages/ws-server/src/webSocketServer.ts | 25 +- .../tests/acceptance/batchRequest.spec.ts | 5 +- .../acceptance/getTransactionByHash.spec.ts | 17 +- .../acceptance/getTransactionCount.spec.ts | 17 +- .../acceptance/getTransactionReceipt.spec.ts | 17 +- .../ws-server/tests/acceptance/index.spec.ts | 18 +- .../tests/acceptance/rateLimiter.spec.ts | 13 +- .../acceptance/sendRawTransaction.spec.ts | 19 +- .../tests/acceptance/subscribe.spec.ts | 46 +- .../acceptance/subscribeNewHeads.spec.ts | 6 +- packages/ws-server/tests/helper/index.ts | 2 +- .../ws-server/tests/unit/validations.spec.ts | 1 - tools/brownie-example/LICENSE | 1 - 73 files changed, 1331 insertions(+), 1255 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index a89ba5d20f..71792f63ff 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -21,29 +21,6 @@ These properties are noted below and should be custom set per deployment. **Note**: The default logging level in the TypeScript application is set to trace. -## Server - -The following table lists the available properties along with their default values for the [Server package](/packages/server/). -Unless you need to set a non-default value, it is recommended to only populate overridden properties in the custom `.env`. - -| Name | Default | Description | -| --------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `BATCH_REQUESTS_ENABLED` | "true" | Flag to disable or enable batch requests. | -| `BATCH_REQUESTS_MAX_SIZE` | "100" | Maximum number of requests allowed in a batch. | -| `CHAIN_ID` | "" | The network chain id. Local and previewnet envs should use `0x12a` (298). Previewnet, Testnet and Mainnet should use `0x129` (297), `0x128` (296) and `0x127` (295) respectively. | -| `HEDERA_NETWORK` | "" | Which network to connect to. Automatically populates the main node & mirror node endpoints. Can be `previewnet`, `testnet`, `mainnet` or a map of network IPs -> node accountIds e.g. `{"127.0.0.1:50211":"0.0.3"}` | -| `INPUT_SIZE_LIMIT` | "1mb" | The [koa-jsonrpc](https://github.com/Bitclimb/koa-jsonrpc) maximum size allowed for requests | -| `LOG_LEVEL ` | "trace" | The logging level for the application. Valid values are `trace`, `debug`, `info`, `warn`, `error`, and `fatal`. | -| `MAX_BLOCK_RANGE` | "5" | The maximum block number greater than the mirror node's latest block to query for | -| `OPERATOR_ID_MAIN` | "" | Operator account ID used to pay for transactions. In `S.R.N` format, e.g. `0.0.1001`. | -| `OPERATOR_KEY_FORMAT` | "DER" | Operator private key format. Valid types are `DER`, `HEX_ECDSA`, or `HEX_ED25519` | -| `OPERATOR_KEY_MAIN` | "" | Operator private key used to sign transactions in hex encoded DER format. This may be either an ED22519 private key or an ECDSA private key. The private key must be associated with/used to derive `OPERATOR_ID_MAIN`. | -| `RATE_LIMIT_DISABLED` | "false" | Flag to disable IP based rate limiting. | -| `REQUEST_ID_IS_OPTIONAL` | "" | Flag to set it the JSON RPC request id field in the body should be optional. Note, this breaks the API spec and is not advised and is provided for test purposes only where some wallets may be non compliant | -| `SERVER_PORT` | "7546" | The RPC server port number to listen for requests on. Currently a static value defaulting to 7546. See [#955](https://github.com/hashgraph/hedera-json-rpc-relay/issues/955) | -| `SERVER_HOST` | undefined | The hostname or IP address on which the server listens for incoming connections. If `SERVER_HOST` is not configured or left undefined (same as `0.0.0.0`), it permits external connections by default, offering more flexibility. | -| `SERVER_REQUEST_TIMEOUT_MS` | "60000" | The time of inactivity allowed before a timeout is triggered and the socket is closed. See [NodeJs Server Timeout](https://nodejs.org/api/http.html#serversettimeoutmsecs-callback) | - ## Relay The following table lists the available properties along with their default values for the [Relay package](/packages/relay/). @@ -54,63 +31,95 @@ Unless you need to set a non-default value, it is recommended to only populate o | `CACHE_MAX` | "1000" | The maximum number (or size) of items that remain in the cache (assuming no TTL pruning or explicit deletions). | | `CACHE_TTL` | "3_600_000" | Max time to live in ms, for items before they are considered stale. Default is one hour in milliseconds | | `CLIENT_TRANSPORT_SECURITY` | "false" | Flag to enable or disable TLS for both networks. | -| `CONTRACT_CALL_GAS_LIMIT` | "50_000_000" | Maximum gas limit applied to eth_call endpoint networks, the Relay will accept up to 50M but keep it capped at 15M for the actual call. | | `CONSENSUS_MAX_EXECUTION_TIME` | "15000" | Maximum time in ms the SDK will wait when submitting a transaction/query before throwing a TIMEOUT error. | +| `CONTRACT_CALL_GAS_LIMIT` | "50_000_000" | Maximum gas limit applied to eth_call endpoint networks, the Relay will accept up to 50M but keep it capped at 15M for the actual call. | +| `CONTRACT_QUERY_TIMEOUT_RETRIES` | "3" | Maximum retries for failed contract call query with timeout exceeded error | +| `DEBUG_API_ENABLED` | "false" | Enables all debug related methods: `debug_traceTransaction` | | `DEFAULT_RATE_LIMIT` | "200" | default fallback rate limit, if no other is configured. | -| `ETH_CALL_CACHE_TTL` | "200" | Maximum time in ms to cache an eth_call response. | +| `ESTIMATE_GAS_THROWS` | "true" | Flag to determine if the system should throw an error with the actual reason during contract reverts instead of returning a predefined gas value. | | `ETH_BLOCK_NUMBER_CACHE_TTL_MS` | "1000" | Time in ms to cache response from mirror node | +| `ETH_CALL_ACCEPTED_ERRORS` | "[]" | A list of acceptable error codes for eth_call requests. If an error code in this list is returned, the request will be retried. | +| `ETH_CALL_CACHE_TTL` | "200" | Maximum time in ms to cache an eth_call response. | +| `ETH_CALL_CONSENSUS_SELECTORS` | "[]" | A comma-separated list of special transaction selectors that should always be routed to the Consensus node. | +| `ETH_CALL_DEFAULT_TO_CONSENSUS_NODE` | "false" | Flag to set if eth_call logic should first query the mirror node. | +| `ETH_FEE_HISTORY_FIXED` | "true" | Flag to set if eth_feeHistory should return a fixed fee for the set of results. | | `ETH_GET_BALANCE_CACHE_TTL_MS` | "1000" | Time in ms to cache balance returned | | `ETH_GET_BLOCK_BY_RESULTS_BATCH_SIZE` | "25" | The number of contract results to request from the Mirror Node per batch durin an eth_getBlockByHash or eth_getBlockByNumber call | | `ETH_GET_GAS_PRICE_CACHE_TTL_MS` | "1_800_000" | Time in ms to cache ethGasPrice returned | -| `ETH_CALL_DEFAULT_TO_CONSENSUS_NODE` | "false" | Flag to set if eth_call logic should first query the mirror node. | -| `ETH_CALL_CONSENSUS_SELECTORS` | [""] | A comma-separated list of special transaction selectors that should always be routed to the Consensus node. | | `ETH_GET_LOGS_BLOCK_RANGE_LIMIT` | "1000" | The maximum block number range to consider during an eth_getLogs call. | | `ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE` | "1000" | The maximum number of transactions to return when running eth_getBlockByHash or eth_getBlockByNumber with transaction objects set to true call. | | `FEE_HISTORY_MAX_RESULTS` | "10" | The maximum number of results to returns as part of `eth_feeHistory`. | -| `ETH_FEE_HISTORY_FIXED` | "true" | Flag to set if eth_feeHistory should return a fixed fee for the set of results. | +| `FILE_APPEND_CHUNK_SIZE=5120` | "5120" | Size in bytes of file chunks for the `HAPI` `FileAppendTransaction` to use during contract creation submissions to consensus nodes as part of `eth_sendRawTransactionsaction`. | +| `FILE_APPEND_MAX_CHUNKS` | "20" | Default maximum number of chunks for the `HAPI` `FileAppendTransaction` to use during contract creation submissions to consensus nodes as part of `eth_sendRawTransactionsaction`. | +| `FILTER_API_ENABLED` | "true" | Enables all filter related methods: `eth_newFilter`, `eth_uninstallFilter`, `eth_getFilterChanges`, `eth_getFilterLogs`, `eth_newBlockFilter` | | `GAS_PRICE_PERCENTAGE_BUFFER` | "0" | The additional buffer that adds a percentage on top of the calculated network gasPrice. This may be used by operators to reduce the chances of `INSUFFICIENT_TX_FEE` errors experienced by users caused by minor fluctuations in the exchange rate. | | `GAS_PRICE_TINY_BAR_BUFFER` | "10000000000" | The additional buffer range to allow during a relay precheck of gas price. This supports slight fluctuations in network gasprice calculations. | -| `HBAR_RATE_LIMIT_DURATION` | "86400000" | HBAR budget limit duration. This creates a timestamp, which resets all limits, when it's reached. Defaults to 1 day. | -| `HBAR_RATE_LIMIT_TINYBAR` | "800000000000" | Total HBAR budget (in tinybars). Defaults to 8000 HBARs. | +| `GET_RECORD_DEFAULT_TO_CONSENSUS_NODE` | "false" | Flag to set if get transaction record logic should first query the mirror node (false) or consensus node via the SDK (true). | +| `HAPI_CLIENT_DURATION_RESET` | "3600000" | Time until client reinitialization. (ms) | +| `HAPI_CLIENT_ERROR_RESET` | [21, 50] | Array of status codes, which when encountered will trigger a reinitialization. Status codes are availble [here](https://github.com/hashgraph/hedera-protobufs/blob/main/services/response_code.proto). | +| `HAPI_CLIENT_TRANSACTION_RESET` | "50" | Number of transaction executions, until client reinitialization. | | `HBAR_RATE_LIMIT_BASIC` | "1120000000" | Individual limit (in tinybars) for spending plans with a BASIC tier. Defaults to 11.2 HBARs. | +| `HBAR_RATE_LIMIT_DURATION` | "86400000" | HBAR budget limit duration. This creates a timestamp, which resets all limits, when it's reached. Defaults to 1 day. | | `HBAR_RATE_LIMIT_EXTENDED` | "3200000000" | Individual limit (in tinybars) for spending plans with a EXTENDED tier. Defaults to 32 HBARs. | | `HBAR_RATE_LIMIT_PRIVILEGED` | "8000000000" | Individual limit (in tinybars) for spending plans with a PRIVILEGED tier. Defaults to 80 HBARs. | +| `HBAR_RATE_LIMIT_TINYBAR` | "800000000000" | Total HBAR budget (in tinybars). Defaults to 8000 HBARs. | | `HBAR_SPENDING_PLANS_CONFIG` | "spendingPlansConfig.json" | The environment variable that either points to a file containing the spending plans, or the JSON content defining the spending plans. | | `HEDERA_SPECIFIC_REVERT_STATUSES` | ["WRONG_NONCE", "INVALID_ACCOUNT_ID"] | A list of specific transaction statuses where each one identifies that the transaction hadn't been executed in the evm but it had reached the services. | -| `HAPI_CLIENT_DURATION_RESET` | "3600000" | Time until client reinitialization. (ms) | -| `HAPI_CLIENT_ERROR_RESET` | [21, 50] | Array of status codes, which when encountered will trigger a reinitialization. Status codes are availble [here](https://github.com/hashgraph/hedera-protobufs/blob/main/services/response_code.proto). | -| `HAPI_CLIENT_TRANSACTION_RESET` | "50" | Number of transaction executions, until client reinitialization. | -| `TEST_INITIAL_ACCOUNT_STARTING_BALANCE` | "2000" | The number of HBars to allocate to the initial account in acceptance test runs. This account is responsible for the gas payment of tests within the suite run session and needs to be adequately funded. | | `LIMIT_DURATION` | "60000" | The maximum duration in ms applied to IP-method based rate limits. | -| `MIRROR_NODE_CONTRACT_RESULTS_PG_MAX` | "25" | The maximum number of pages to be requested for contract results from the mirror node. | +| `MIRROR_NODE_AGENT_CACHEABLE_DNS` | "true" | Flag to set if the mirror node agent should cacheable DNS lookups, using better-lookup library. | | `MIRROR_NODE_CONTRACT_RESULTS_LOGS_PG_MAX` | "200" | The maximum number of pages to be requested for contract results logs from the mirror node. (each page will contain a max of 100 results) | +| `MIRROR_NODE_CONTRACT_RESULTS_PG_MAX` | "25" | The maximum number of pages to be requested for contract results from the mirror node. | +| `MIRROR_NODE_HTTP_KEEP_ALIVE` | true | Flag indicating whether to keep HTTP connections alive for requests to the mirror node. | +| `MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS` | 1000 | The maximum time in milliseconds to keep HTTP connections alive for requests to the mirror node. | +| `MIRROR_NODE_HTTP_MAX_SOCKETS` | 300 | The maximum number of sockets to be used for HTTP connections to the mirror node. | +| `MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS` | 300 | The maximum number of total sockets to be used for HTTP connections to the mirror node. | | `MIRROR_NODE_LIMIT_PARAM` | "100" | The mirror node custom limit value to be set on GET requests. This optimizes the flow to reduce the number of calls made to the mirror node by setting a limit larger than it's default limit. | +| `MIRROR_NODE_MAX_REDIRECTS` | 5 | The maximum number of redirects allowed when making requests to the mirror node before timing out. | +| `MIRROR_NODE_REQUEST_RETRY_COUNT` | "10" | Maximun amount of retries to repeat on `GetContractResults` `contracts/results/)` requests when fetching contract results after eth_sendRawTransaction submission. \*Note that this in addition and multiplies the configured Axios retries values. | | `MIRROR_NODE_RETRIES` | "0" | The maximum number of retries on a GET request to the mirror node when an acceptable error code is returned. | +| `MIRROR_NODE_RETRIES_DEVMODE` | "5" | The maximum number of retries on a GET request to the mirror node when an acceptable error code is returned in dev mode. | | `MIRROR_NODE_RETRY_CODES` | "[]" | The acceptable error codes to retry on a request to the mirror node. If more than 1 error is defined value should be like ie: [400,404,500] | | `MIRROR_NODE_RETRY_DELAY` | "2000" | The delay in ms between retry requests. | -| `MIRROR_NODE_RETRIES_DEVMODE` | "5" | The maximum number of retries on a GET request to the mirror node when an acceptable error code is returned in dev mode. | | `MIRROR_NODE_RETRY_DELAY_DEVMODE` | "200" | The delay in ms between retry requests in dev mode. | +| `MIRROR_NODE_TIMEOUT` | 1000 | The maximum time in ms to wait for a response from the mirror node before timing out. | | `MIRROR_NODE_URL` | "" | The Mirror Node API endpoint. Official endpoints are Previewnet (https://previewnet.mirrornode.hedera.com), Testnet (https://testnet.mirrornode.hedera.com), Mainnet (https://mainnet-public.mirrornode.hedera.com). See [Mirror Node REST API](https://docs.hedera.com/hedera/sdks-and-apis/rest-api) | | `MIRROR_NODE_URL_HEADER_X_API_KEY` | "" | Authentication for a `MIRROR_NODE_URL` that requires authentication via the `x-api-key` header. | -| `MIRROR_NODE_REQUEST_RETRY_COUNT` | "10" | Maximun amount of retries to repeat on `GetContractResults` `contracts/results/)` requests when fetching contract results after eth_sendRawTransaction submission. \*Note that this in addition and multiplies the configured Axios retries values. | -| `MIRROR_NODE_AGENT_CACHEABLE_DNS` | "true" | Flag to set if the mirror node agent should cacheable DNS lookups, using better-lookup library. | +| `MULTI_SET` | "false" | Switch between different implementation of setting multiple K/V pairs in the shared cache. True is mSet, false is pipeline | +| `REDIS_ENABLED` | "true" | Enable usage of Redis as shared cache | +| `REDIS_RECONNECT_DELAY_MS` | "1000" | Sets the delay between reconnect retries from the Redis client in ms | +| `REDIS_URL` | "redis://127.0.0.1:6379" | Sets the url for the Redis shared cache | | `SDK_REQUEST_TIMEOUT` | "10000" | The complete timeout for running the SDK `execute()` method. This controls the GRPC channel timeout config when querying with network nodes. | -| `CONTRACT_QUERY_TIMEOUT_RETRIES` | "3" | Maximum retries for failed contract call query with timeout exceeded error | +| `SEND_RAW_TRANSACTION_SIZE_LIMIT` | "131072" | Sets the limit of the transaction size the relay accepts on eth_sendRawTransaction | +| `TEST_GAS_PRICE_DEVIATION` | "0.2" | The additional buffer range to allow during a relay precheck of gas price. This supports slight fluctuations in network gasprice calculations. | +| `TEST_INITIAL_ACCOUNT_STARTING_BALANCE` | "2000" | The number of HBars to allocate to the initial account in acceptance test runs. This account is responsible for the gas payment of tests within the suite run session and needs to be adequately funded. | | `TIER_1_RATE_LIMIT` | "100" | Maximum restrictive request count limit used for expensive endpoints rate limiting. | | `TIER_2_RATE_LIMIT` | "800" | Maximum moderate request count limit used for non expensive endpoints. | | `TIER_3_RATE_LIMIT` | "1600" | Maximum relaxed request count limit used for static return endpoints. | | `TX_DEFAULT_GAS` | "400000" | Default gas for transactions that do not specify gas. | | `USE_ASYNC_TX_PROCESSING` | "false" | Set to `true` to enable `eth_sendRawTransaction` to return the transaction hash immediately after passing all prechecks, while processing the transaction asynchronously in the background. | -| `FILE_APPEND_MAX_CHUNKS` | "20" | Default maximum number of chunks for the `HAPI` `FileAppendTransaction` to use during contract creation submissions to consensus nodes as part of `eth_sendRawTransactionsaction`. | -| `FILE_APPEND_CHUNK_SIZE=5120` | "5120" | Size in bytes of file chunks for the `HAPI` `FileAppendTransaction` to use during contract creation submissions to consensus nodes as part of `eth_sendRawTransactionsaction`. | -| `FILTER_API_ENABLED` | "false" | Enables all filter related methods: `eth_newFilter`, `eth_uninstallFilter`, `eth_getFilterChanges`, `eth_getFilterLogs`, `eth_newBlockFilter` | -| `DEBUG_API_ENABLED` | "false" | Enables all debug related methods: `debug_traceTransaction` | -| `REDIS_ENABLED` | "true" | Enable usage of Redis as shared cache | -| `REDIS_URL` | "redis://127.0.0.1:6379" | Sets the url for the Redis shared cache | -| `MULTI_SET` | "true" | Switch between different implementation of setting multiple K/V pairs in the shared cache. True is mSet, false is pipeline | -| `REDIS_RECONNECT_DELAY_MS` | "1000" | Sets the delay between reconnect retries from the Redis client in ms | -| `SEND_RAW_TRANSACTION_SIZE_LIMIT` | "131072" | Sets the limit of the transaction size the relay accepts on eth_sendRawTransaction | -| `GET_RECORD_DEFAULT_TO_CONSENSUS_NODE` | "false" | Flag to set if get transaction record logic should first query the mirror node (false) or consensus node via the SDK (true). | + +## Server + +The following table lists the available properties along with their default values for the [Server package](/packages/server/). +Unless you need to set a non-default value, it is recommended to only populate overridden properties in the custom `.env`. + +| Name | Default | Description | +| --------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `BATCH_REQUESTS_ENABLED` | "true" | Flag to disable or enable batch requests. | +| `BATCH_REQUESTS_MAX_SIZE` | "100" | Maximum number of requests allowed in a batch. | +| `CHAIN_ID` | "" | The network chain id. Local and previewnet envs should use `0x12a` (298). Previewnet, Testnet and Mainnet should use `0x129` (297), `0x128` (296) and `0x127` (295) respectively. | +| `HEDERA_NETWORK` | "" | Which network to connect to. Automatically populates the main node & mirror node endpoints. Can be `previewnet`, `testnet`, `mainnet` or a map of network IPs -> node accountIds e.g. `{"127.0.0.1:50211":"0.0.3"}` | +| `INPUT_SIZE_LIMIT` | "1mb" | The [koa-jsonrpc](https://github.com/Bitclimb/koa-jsonrpc) maximum size allowed for requests | +| `LOG_LEVEL ` | "trace" | The logging level for the application. Valid values are `trace`, `debug`, `info`, `warn`, `error`, and `fatal`. | +| `MAX_BLOCK_RANGE` | "5" | The maximum block number greater than the mirror node's latest block to query for | +| `OPERATOR_ID_MAIN` | "" | Operator account ID used to pay for transactions. In `S.R.N` format, e.g. `0.0.1001`. | +| `OPERATOR_KEY_FORMAT` | "DER" | Operator private key format. Valid types are `DER`, `HEX_ECDSA`, or `HEX_ED25519` | +| `OPERATOR_KEY_MAIN` | "" | Operator private key used to sign transactions in hex encoded DER format. This may be either an ED22519 private key or an ECDSA private key. The private key must be associated with/used to derive `OPERATOR_ID_MAIN`. | +| `RATE_LIMIT_DISABLED` | "false" | Flag to disable IP based rate limiting. | +| `REQUEST_ID_IS_OPTIONAL` | "false" | Flag to set it the JSON RPC request id field in the body should be optional. Note, this breaks the API spec and is not advised and is provided for test purposes only where some wallets may be non compliant | +| `SERVER_HOST` | undefined | The hostname or IP address on which the server listens for incoming connections. If `SERVER_HOST` is not configured or left undefined (same as `0.0.0.0`), it permits external connections by default, offering more flexibility. | +| `SERVER_PORT` | "7546" | The RPC server port number to listen for requests on. Currently a static value defaulting to 7546. See [#955](https://github.com/hashgraph/hedera-json-rpc-relay/issues/955) | +| `SERVER_REQUEST_TIMEOUT_MS` | "60000" | The time of inactivity allowed before a timeout is triggered and the socket is closed. See [NodeJs Server Timeout](https://nodejs.org/api/http.html#serversettimeoutmsecs-callback) | ## WS-Server @@ -119,22 +128,22 @@ Unless you need to set a non-default value, it is recommended to only populate o | Name | Default | Description | | ------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `WS_BATCH_REQUESTS_ENABLED` | "true" | Flag to disable or enable batch requests on the websocket server. | -| `WS_BATCH_REQUESTS_MAX_SIZE` | "20" | Maximum number of requests allowed in a batch on websocket server. | | `SUBSCRIPTIONS_ENABLED` | "false" | If enabled eth_subscribe will be enabled using WebSockets. | -| `WS_MAX_INACTIVITY_TTL` | "300000" | Time in ms that the web socket connection is allowed to stay open without any messages sent or received, currently 5 minutes. | -| `WS_CONNECTION_LIMIT` | "10" | Maximum amount of concurrent web socket connections allowed. | -| `WS_POLLING_INTERVAL` | "500" | Time in ms in between each poll to mirror node while there are subscriptions. | -| `WEB_SOCKET_PORT` | "8546" | Port for the web socket connections | | `WEB_SOCKET_HOST` | "localhost" | The hostname or IP address on which the server will listen for incoming connections. | | `WEB_SOCKET_HTTP_PORT` | "8547" | Port for standard http server, used for metrics and health status endpoints | -| `WS_SUBSCRIPTION_LIMIT` | "10" | Maximum amount of subscriptions per single connection | +| `WEB_SOCKET_PORT` | "8546" | Port for the web socket connections | +| `WS_BATCH_REQUESTS_ENABLED` | "true" | Flag to disable or enable batch requests on the websocket server. | +| `WS_BATCH_REQUESTS_MAX_SIZE` | "20" | Maximum number of requests allowed in a batch on websocket server. | +| `WS_CACHE_TTL` | "20000" | The time to live for cached entries. | +| `WS_CONNECTION_LIMIT` | "10" | Maximum amount of concurrent web socket connections allowed. | | `WS_CONNECTION_LIMIT_PER_IP` | "10" | Maximum amount of connections from a single IP address | +| `WS_MAX_INACTIVITY_TTL` | "300000" | Time in ms that the web socket connection is allowed to stay open without any messages sent or received, currently 5 minutes. | | `WS_MULTIPLE_ADDRESSES_ENABLED` | "false" | If enabled eth_subscribe will allow subscription to multiple contract address. | -| `WS_CACHE_TTL` | "20000" | The time to live for cached entries. | | `WS_NEW_HEADS_ENABLED`. | "true" | Enables subscriptions for the latest blocks, `newHeads`. | | `WS_PING_INTERVAL` | "100000" | Interval between ping messages. Set to `0` to disable pinger. | +| `WS_POLLING_INTERVAL` | "500" | Time in ms in between each poll to mirror node while there are subscriptions. | | `WS_SAME_SUB_FOR_SAME_EVENT` | "true" | The relay will return the same subscription ID when a client subscribes to the same event multiple times using a single connection. When set to false, the relay will always create a new subscription ID for each `eth_subscribe` request. | +| `WS_SUBSCRIPTION_LIMIT` | "10" | Maximum amount of subscriptions per single connection | ## Sample for connecting to Hedera Environments @@ -185,12 +194,12 @@ Unless you need to set a non-default value, it is recommended to only populate o | Name | Default | Description | | ---------------------------------------- | ------- | -------------------------------------------------------------------------------------------------- | -| `LOCAL_NODE` | "" | Flag if relay is hosted in the Hedera local node setup. | -| `E2E_RELAY_HOST` | "" | Remote relay url to point to. | | `DEV_MODE` | "false" | Flag if relay should operate in developer optimization mode. | -| `TEST_WS_SERVER` | "false" | Flag config for enable or disable the WS server tests. | +| `E2E_RELAY_HOST` | "" | Remote relay url to point to. | +| `LOCAL_NODE` | "" | Flag if relay is hosted in the Hedera local node setup. | | `TEST_GAS_PRICE_DEVIATION` | 0.2 | Value to use as deviation when comparing gas prices in the rpc-batch1.spec.ts | | `TEST_TRANSACTION_RECORD_COST_TOLERANCE` | 0.02 | Defines the acceptable tolerance level for discrepancies in transaction record costs during tests. | +| `TEST_WS_SERVER` | "false" | Flag config for enable or disable the WS server tests. | For test context additional fields need to be set. The following example showcases a `hedera-local-node` instance (where values match those noted on [Local Node Network Variables](https://github.com/hashgraph/hedera-local-node#network-variables) diff --git a/packages/config-service/src/services/globalConfig.ts b/packages/config-service/src/services/globalConfig.ts index f44eda0c8b..0ecbabd8f8 100644 --- a/packages/config-service/src/services/globalConfig.ts +++ b/packages/config-service/src/services/globalConfig.ts @@ -18,729 +18,804 @@ * */ +/** + * Extracts the type string associated with a specific key in the `_CONFIG` object. + * If the key `K` exists in `_CONFIG`, it retrieves the 'type' property; otherwise, it resolves to `never`. + * + * Example: + * - `'OPERATOR_ID_MAIN'` → `'string'` (if defined in `_CONFIG`) + * - `'INVALID_KEY'` → `never` + */ +type ExtractTypeStringFromKey = K extends keyof typeof _CONFIG ? (typeof _CONFIG)[K]['type'] : never; + +/** + * Maps string representations of types (`'string'`, `'boolean'`, `'number'`) to their actual TypeScript types. + * + * Example: + * - `'string'` → string + * - `'boolean'` → boolean + * - `'number'` → number + */ +type StringTypeToActualType = Tstr extends 'string' + ? string + : Tstr extends 'boolean' + ? boolean + : Tstr extends 'number' + ? number + : never; + +/** + * Determines if a configuration value can be `undefined` based on two conditions: + * - It must be optional (`required: false`) + * - It must have no default value (`defaultValue: null`) + * + * Example: + * - `'OPERATOR_ID_MAIN'` (`required: true`, `defaultValue: null`) → `false` + * - `'WEB_SOCKET_PORT'` (`required: false`, `defaultValue: 8546`) → `false` + * - `'GITHUB_PR_NUMBER'` (`required: false`, `defaultValue: null`) → `true` + */ +type CanBeUndefined = K extends keyof typeof _CONFIG + ? (typeof _CONFIG)[K]['required'] extends true + ? false + : (typeof _CONFIG)[K]['defaultValue'] extends null + ? true + : false + : never; + +/** + * Maps configuration keys to their corresponding TypeScript types, + * including `undefined` when applicable based on the configuration. + * + * Example: + * - `'OPERATOR_ID_MAIN'` (`type: 'string'`, `required: true`, `defaultValue: null`) → `string` + * - `'WEB_SOCKET_PORT'` (`type: 'number'`, `required: false`, `defaultValue: 8546`) → `number` + * - `'GITHUB_PR_NUMBER'` (`type: 'string'`, `required: false`, `defaultValue: null`) → `string | undefined` + */ +export type GetTypeOfConfigKey = CanBeUndefined extends true + ? StringTypeToActualType> | undefined + : StringTypeToActualType>; + +/** + * Interface defining the structure of a configuration property. + */ export interface ConfigProperty { - envName: string; - type: string; - required: boolean; - defaultValue: string | number | boolean | null; + envName: string; // Environment variable name + type: 'string' | 'number' | 'boolean'; // Data type of the configuration property + required: boolean; // Whether the property is required + defaultValue: string | number | boolean | null; // Default value (if any) } +/** + * Configuration object defining various properties and their metadata. + * Each property is an object that contains information about the environment variable, + * its type, whether it is required, and its default value. + */ +const _CONFIG = { + BATCH_REQUESTS_ENABLED: { + envName: 'BATCH_REQUESTS_ENABLED', + type: 'boolean', + required: false, + defaultValue: true, + }, + BATCH_REQUESTS_MAX_SIZE: { + envName: 'BATCH_REQUESTS_MAX_SIZE', + type: 'number', + required: false, + defaultValue: 100, + }, + CACHE_MAX: { + envName: 'CACHE_MAX', + type: 'number', + required: false, + defaultValue: 1000, + }, + CACHE_TTL: { + envName: 'CACHE_TTL', + type: 'number', + required: false, + defaultValue: 3600000, + }, + CHAIN_ID: { + envName: 'CHAIN_ID', + type: 'string', + required: true, + defaultValue: '0x12a', + }, + CLIENT_TRANSPORT_SECURITY: { + envName: 'CLIENT_TRANSPORT_SECURITY', + type: 'boolean', + required: false, + defaultValue: false, + }, + CONSENSUS_MAX_EXECUTION_TIME: { + envName: 'CONSENSUS_MAX_EXECUTION_TIME', + type: 'number', + required: false, + defaultValue: 15000, + }, + CONTRACT_CALL_GAS_LIMIT: { + envName: 'CONTRACT_CALL_GAS_LIMIT', + type: 'number', + required: false, + defaultValue: 50_000_000, + }, + CONTRACT_QUERY_TIMEOUT_RETRIES: { + envName: 'CONTRACT_QUERY_TIMEOUT_RETRIES', + type: 'number', + required: false, + defaultValue: 3, + }, + DEBUG_API_ENABLED: { + envName: 'DEBUG_API_ENABLED', + type: 'boolean', + required: false, + defaultValue: false, + }, + DEFAULT_RATE_LIMIT: { + envName: 'DEFAULT_RATE_LIMIT', + type: 'number', + required: false, + defaultValue: 200, + }, + DEV_MODE: { + envName: 'DEV_MODE', + type: 'boolean', + required: false, + defaultValue: false, + }, + E2E_RELAY_HOST: { + envName: 'E2E_RELAY_HOST', + type: 'string', + required: false, + defaultValue: 'http://localhost:7546', + }, + E2E_SERVER_PORT: { + envName: 'E2E_SERVER_PORT', + type: 'number', + required: false, + defaultValue: 7546, + }, + ESTIMATE_GAS_THROWS: { + envName: 'ESTIMATE_GAS_THROWS', + type: 'boolean', + required: false, + defaultValue: true, + }, + ETH_BLOCK_NUMBER_CACHE_TTL_MS: { + envName: 'ETH_BLOCK_NUMBER_CACHE_TTL_MS', + type: 'number', + required: false, + defaultValue: 1000, + }, + ETH_CALL_ACCEPTED_ERRORS: { + envName: 'ETH_CALL_ACCEPTED_ERRORS', + type: 'string', + required: false, + defaultValue: '[]', + }, + ETH_CALL_CACHE_TTL: { + envName: 'ETH_CALL_CACHE_TTL', + type: 'number', + required: false, + defaultValue: 200, + }, + ETH_CALL_CONSENSUS_SELECTORS: { + envName: 'ETH_CALL_CONSENSUS_SELECTORS', + type: 'string', + required: false, + defaultValue: '[]', + }, + ETH_CALL_DEFAULT_TO_CONSENSUS_NODE: { + envName: 'ETH_CALL_DEFAULT_TO_CONSENSUS_NODE', + type: 'boolean', + required: false, + defaultValue: false, + }, + ETH_FEE_HISTORY_FIXED: { + envName: 'ETH_FEE_HISTORY_FIXED', + type: 'boolean', + required: false, + defaultValue: true, + }, + ETH_GET_BALANCE_CACHE_TTL_MS: { + envName: 'ETH_GET_BALANCE_CACHE_TTL_MS', + type: 'number', + required: false, + defaultValue: 1000, + }, + ETH_GET_GAS_PRICE_CACHE_TTL_MS: { + envName: 'ETH_GET_GAS_PRICE_CACHE_TTL_MS', + type: 'number', + required: false, + defaultValue: 1_800_000, // half an hour + }, + ETH_GET_LOGS_BLOCK_RANGE_LIMIT: { + envName: 'ETH_GET_LOGS_BLOCK_RANGE_LIMIT', + type: 'number', + required: false, + defaultValue: 1000, + }, + ETH_GET_TRANSACTION_COUNT_CACHE_TTL: { + envName: 'ETH_GET_TRANSACTION_COUNT_CACHE_TTL', + type: 'number', + required: false, + defaultValue: 500, + }, + ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE: { + envName: 'ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE', + type: 'number', + required: false, + defaultValue: 1000, + }, + HEDERA_SPECIFIC_REVERT_STATUSES: { + envName: 'HEDERA_SPECIFIC_REVERT_STATUSES', + type: 'string', + required: false, + defaultValue: '["WRONG_NONCE", "INVALID_ACCOUNT_ID"]', + }, + FEE_HISTORY_MAX_RESULTS: { + envName: 'FEE_HISTORY_MAX_RESULTS', + type: 'number', + required: false, + defaultValue: 10, + }, + FILE_APPEND_CHUNK_SIZE: { + envName: 'FILE_APPEND_CHUNK_SIZE', + type: 'number', + required: false, + defaultValue: 5120, + }, + FILE_APPEND_MAX_CHUNKS: { + envName: 'FILE_APPEND_MAX_CHUNKS', + type: 'number', + required: false, + defaultValue: 20, + }, + FILTER_API_ENABLED: { + envName: 'FILTER_API_ENABLED', + type: 'boolean', + required: false, + defaultValue: true, + }, + FILTER_TTL: { + envName: 'FILTER_TTL', + type: 'number', + required: false, + defaultValue: 300000, + }, + GAS_PRICE_PERCENTAGE_BUFFER: { + envName: 'GAS_PRICE_PERCENTAGE_BUFFER', + type: 'number', + required: false, + defaultValue: 0, + }, + GAS_PRICE_TINY_BAR_BUFFER: { + envName: 'GAS_PRICE_TINY_BAR_BUFFER', + type: 'number', + required: false, + defaultValue: 10000000000, + }, + GET_RECORD_DEFAULT_TO_CONSENSUS_NODE: { + envName: 'GET_RECORD_DEFAULT_TO_CONSENSUS_NODE', + type: 'boolean', + required: false, + defaultValue: false, + }, + GH_ACCESS_TOKEN: { + envName: 'GH_ACCESS_TOKEN', + type: 'string', + required: false, + defaultValue: null, + }, + GITHUB_PR_NUMBER: { + envName: 'GITHUB_PR_NUMBER', + type: 'string', + required: false, + defaultValue: null, + }, + GITHUB_REPOSITORY: { + envName: 'GITHUB_REPOSITORY', + type: 'string', + required: false, + defaultValue: null, + }, + GITHUB_TOKEN: { + envName: 'GITHUB_TOKEN', + type: 'string', + required: false, + defaultValue: null, + }, + HAPI_CLIENT_DURATION_RESET: { + envName: 'HAPI_CLIENT_DURATION_RESET', + type: 'number', + required: false, + defaultValue: 3600000, + }, + HAPI_CLIENT_ERROR_RESET: { + envName: 'HAPI_CLIENT_ERROR_RESET', + type: 'string', + required: false, + defaultValue: '[21, 50]', + }, + HAPI_CLIENT_TRANSACTION_RESET: { + envName: 'HAPI_CLIENT_TRANSACTION_RESET', + type: 'number', + required: false, + defaultValue: 50, + }, + HBAR_RATE_LIMIT_BASIC: { + envName: 'HBAR_RATE_LIMIT_BASIC', + type: 'number', + required: false, + defaultValue: 1_120_000_000, // 11.2 hbar + }, + HBAR_RATE_LIMIT_EXTENDED: { + envName: 'HBAR_RATE_LIMIT_EXTENDED', + type: 'number', + required: false, + defaultValue: 3_200_000_000, // 32 hbar + }, + HBAR_RATE_LIMIT_PRIVILEGED: { + envName: 'HBAR_RATE_LIMIT_PRIVILEGED', + type: 'number', + required: false, + defaultValue: 8_000_000_000, // 80 hbar + }, + HBAR_RATE_LIMIT_DURATION: { + envName: 'HBAR_RATE_LIMIT_DURATION', + type: 'number', + required: false, + defaultValue: 86_400_000, // 24 hours + }, + HBAR_RATE_LIMIT_TINYBAR: { + envName: 'HBAR_RATE_LIMIT_TINYBAR', + type: 'number', + required: false, + defaultValue: 800_000_000_000, // 8000 hbar + }, + HEDERA_NETWORK: { + envName: 'HEDERA_NETWORK', + type: 'string', + required: true, + defaultValue: null, + }, + HBAR_SPENDING_PLANS_CONFIG: { + envName: 'HBAR_SPENDING_PLANS_CONFIG', + type: 'string', + required: false, + defaultValue: 'spendingPlansConfig.json', + }, + INITIAL_BALANCE: { + envName: 'INITIAL_BALANCE', + type: 'number', + required: false, + defaultValue: 5000000000, + }, + INPUT_SIZE_LIMIT: { + envName: 'INPUT_SIZE_LIMIT', + type: 'number', + required: false, + defaultValue: 1, + }, + LIMIT_DURATION: { + envName: 'LIMIT_DURATION', + type: 'number', + required: false, + defaultValue: 60000, + }, + LOCAL_NODE: { + envName: 'LOCAL_NODE', + type: 'boolean', + required: false, + defaultValue: null, + }, + LOG_LEVEL: { + envName: 'LOG_LEVEL', + type: 'string', + required: false, + defaultValue: 'trace', + }, + MAX_BLOCK_RANGE: { + envName: 'MAX_BLOCK_RANGE', + type: 'number', + required: false, + defaultValue: 5, + }, + MEMWATCH_ENABLED: { + envName: 'MEMWATCH_ENABLED', + type: 'boolean', + required: false, + defaultValue: null, + }, + MIRROR_NODE_AGENT_CACHEABLE_DNS: { + envName: 'MIRROR_NODE_AGENT_CACHEABLE_DNS', + type: 'boolean', + required: false, + defaultValue: true, + }, + MIRROR_NODE_CONTRACT_RESULTS_LOGS_PG_MAX: { + envName: 'MIRROR_NODE_CONTRACT_RESULTS_LOGS_PG_MAX', + type: 'number', + required: false, + defaultValue: 200, + }, + MIRROR_NODE_CONTRACT_RESULTS_PG_MAX: { + envName: 'MIRROR_NODE_CONTRACT_RESULTS_PG_MAX', + type: 'number', + required: false, + defaultValue: 25, + }, + MIRROR_NODE_HTTP_KEEP_ALIVE: { + envName: 'MIRROR_NODE_HTTP_KEEP_ALIVE', + type: 'boolean', + required: false, + defaultValue: true, + }, + MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS: { + envName: 'MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS', + type: 'number', + required: false, + defaultValue: 1000, + }, + MIRROR_NODE_HTTP_MAX_SOCKETS: { + envName: 'MIRROR_NODE_HTTP_MAX_SOCKETS', + type: 'number', + required: false, + defaultValue: 300, + }, + MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS: { + envName: 'MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS', + type: 'number', + required: false, + defaultValue: 300, + }, + MIRROR_NODE_HTTP_SOCKET_TIMEOUT: { + envName: 'MIRROR_NODE_HTTP_SOCKET_TIMEOUT', + type: 'number', + required: false, + defaultValue: 60000, + }, + MIRROR_NODE_LIMIT_PARAM: { + envName: 'MIRROR_NODE_LIMIT_PARAM', + type: 'number', + required: false, + defaultValue: 100, + }, + MIRROR_NODE_MAX_REDIRECTS: { + envName: 'MIRROR_NODE_MAX_REDIRECTS', + type: 'number', + required: false, + defaultValue: 5, + }, + MIRROR_NODE_RETRIES: { + envName: 'MIRROR_NODE_RETRIES', + type: 'number', + required: false, + defaultValue: 0, + }, + MIRROR_NODE_RETRIES_DEVMODE: { + envName: 'MIRROR_NODE_RETRIES_DEVMODE', + type: 'number', + required: false, + defaultValue: 5, + }, + MIRROR_NODE_RETRY_CODES: { + envName: 'MIRROR_NODE_RETRY_CODES', + type: 'string', + required: false, + defaultValue: '[]', + }, + MIRROR_NODE_RETRY_DELAY: { + envName: 'MIRROR_NODE_RETRY_DELAY', + type: 'number', + required: false, + defaultValue: 2000, + }, + MIRROR_NODE_RETRY_DELAY_DEVMODE: { + envName: 'MIRROR_NODE_RETRY_DELAY_DEVMODE', + type: 'number', + required: false, + defaultValue: 200, + }, + MIRROR_NODE_REQUEST_RETRY_COUNT: { + envName: 'MIRROR_NODE_REQUEST_RETRY_COUNT', + type: 'number', + required: false, + defaultValue: 10, + }, + MIRROR_NODE_TIMEOUT: { + envName: 'MIRROR_NODE_TIMEOUT', + type: 'number', + required: false, + defaultValue: 10000, + }, + MIRROR_NODE_URL: { + envName: 'MIRROR_NODE_URL', + type: 'string', + required: true, + defaultValue: null, + }, + MIRROR_NODE_URL_HEADER_X_API_KEY: { + envName: 'MIRROR_NODE_URL_HEADER_X_API_KEY', + type: 'string', + required: false, + defaultValue: null, + }, + MIRROR_NODE_URL_WEB3: { + envName: 'MIRROR_NODE_URL_WEB3', + type: 'string', + required: false, + defaultValue: null, + }, + MULTI_SET: { + envName: 'MULTI_SET', + type: 'boolean', + required: false, + defaultValue: false, + }, + // the actual env var in the node process is npm_package_version + npm_package_version: { + envName: 'npm_package_version', + type: 'string', + required: true, + defaultValue: null, + }, + OPERATOR_ID_ETH_SENDRAWTRANSACTION: { + envName: 'OPERATOR_ID_ETH_SENDRAWTRANSACTION', + type: 'string', + required: false, + defaultValue: null, + }, + OPERATOR_ID_MAIN: { + envName: 'OPERATOR_ID_MAIN', + type: 'string', + required: true, + defaultValue: null, + }, + OPERATOR_KEY_ETH_SENDRAWTRANSACTION: { + envName: 'OPERATOR_KEY_ETH_SENDRAWTRANSACTION', + type: 'string', + required: false, + defaultValue: null, + }, + OPERATOR_KEY_FORMAT: { + envName: 'OPERATOR_KEY_FORMAT', + type: 'string', + required: false, + defaultValue: null, + }, + OPERATOR_KEY_MAIN: { + envName: 'OPERATOR_KEY_MAIN', + type: 'string', + required: true, + defaultValue: null, + }, + RATE_LIMIT_DISABLED: { + envName: 'RATE_LIMIT_DISABLED', + type: 'boolean', + required: false, + defaultValue: false, + }, + REDIS_ENABLED: { + envName: 'REDIS_ENABLED', + type: 'boolean', + required: false, + defaultValue: true, + }, + REDIS_RECONNECT_DELAY_MS: { + envName: 'REDIS_RECONNECT_DELAY_MS', + type: 'number', + required: false, + defaultValue: 1000, + }, + REDIS_URL: { + envName: 'REDIS_URL', + type: 'string', + required: false, + defaultValue: 'redis://127.0.0.1:6379', + }, + REQUEST_ID_IS_OPTIONAL: { + envName: 'REQUEST_ID_IS_OPTIONAL', + type: 'boolean', + required: false, + defaultValue: false, + }, + SDK_REQUEST_TIMEOUT: { + envName: 'SDK_REQUEST_TIMEOUT', + type: 'number', + required: false, + defaultValue: 10000, + }, + SEND_RAW_TRANSACTION_SIZE_LIMIT: { + envName: 'SEND_RAW_TRANSACTION_SIZE_LIMIT', + type: 'number', + required: false, + defaultValue: 131072, + }, + SERVER_HOST: { + envName: 'SERVER_HOST', + type: 'string', + required: false, + defaultValue: null, + }, + SERVER_PORT: { + envName: 'SERVER_PORT', + type: 'number', + required: false, + defaultValue: 7546, + }, + SERVER_REQUEST_TIMEOUT_MS: { + envName: 'SERVER_REQUEST_TIMEOUT_MS', + type: 'number', + required: false, + defaultValue: 60000, + }, + SUBSCRIPTIONS_ENABLED: { + envName: 'SUBSCRIPTIONS_ENABLED', + type: 'boolean', + required: false, + defaultValue: false, + }, + TEST: { + envName: 'TEST', + type: 'boolean', + required: false, + defaultValue: null, + }, + TEST_GAS_PRICE_DEVIATION: { + envName: 'TEST_GAS_PRICE_DEVIATION', + type: 'number', + required: false, + defaultValue: 0.2, + }, + TEST_INITIAL_ACCOUNT_STARTING_BALANCE: { + envName: 'TEST_INITIAL_ACCOUNT_STARTING_BALANCE', + type: 'number', + required: false, + defaultValue: 2000, + }, + TEST_TRANSACTION_RECORD_COST_TOLERANCE: { + envName: 'TEST_TRANSACTION_RECORD_COST_TOLERANCE', + type: 'number', + required: false, + defaultValue: 0.02, + }, + TEST_WS_SERVER: { + envName: 'TEST_WS_SERVER', + type: 'boolean', + required: false, + defaultValue: false, + }, + TIER_1_RATE_LIMIT: { + envName: 'TIER_1_RATE_LIMIT', + type: 'number', + required: false, + defaultValue: 100, + }, + TIER_2_RATE_LIMIT: { + envName: 'TIER_2_RATE_LIMIT', + type: 'number', + required: false, + defaultValue: 800, + }, + TIER_3_RATE_LIMIT: { + envName: 'TIER_3_RATE_LIMIT', + type: 'number', + required: false, + defaultValue: 1600, + }, + TX_DEFAULT_GAS: { + envName: 'TX_DEFAULT_GAS', + type: 'number', + required: false, + defaultValue: null, + }, + USE_ASYNC_TX_PROCESSING: { + envName: 'USE_ASYNC_TX_PROCESSING', + type: 'boolean', + required: false, + defaultValue: false, + }, + WEB_SOCKET_HTTP_PORT: { + envName: 'WEB_SOCKET_HTTP_PORT', + type: 'number', + required: false, + defaultValue: 8547, + }, + WEB_SOCKET_PORT: { + envName: 'WEB_SOCKET_PORT', + type: 'number', + required: false, + defaultValue: 8546, + }, + WRITE_SNAPSHOT_ON_MEMORY_LEAK: { + envName: 'WRITE_SNAPSHOT_ON_MEMORY_LEAK', + type: 'boolean', + required: false, + defaultValue: null, + }, + WS_BATCH_REQUESTS_ENABLED: { + envName: 'WS_BATCH_REQUESTS_ENABLED', + type: 'boolean', + required: false, + defaultValue: true, + }, + WS_BATCH_REQUESTS_MAX_SIZE: { + envName: 'WS_BATCH_REQUESTS_MAX_SIZE', + type: 'number', + required: false, + defaultValue: 20, + }, + WS_CACHE_TTL: { + envName: 'WS_CACHE_TTL', + type: 'number', + required: false, + defaultValue: 20000, + }, + WS_CONNECTION_LIMIT: { + envName: 'WS_CONNECTION_LIMIT', + type: 'number', + required: false, + defaultValue: 10, + }, + WS_CONNECTION_LIMIT_PER_IP: { + envName: 'WS_CONNECTION_LIMIT_PER_IP', + type: 'number', + required: false, + defaultValue: 10, + }, + WS_MAX_INACTIVITY_TTL: { + envName: 'WS_MAX_INACTIVITY_TTL', + type: 'number', + required: false, + defaultValue: 300000, + }, + WS_MULTIPLE_ADDRESSES_ENABLED: { + envName: 'WS_MULTIPLE_ADDRESSES_ENABLED', + type: 'boolean', + required: false, + defaultValue: false, + }, + WS_NEW_HEADS_ENABLED: { + envName: 'WS_NEW_HEADS_ENABLED', + type: 'boolean', + required: false, + defaultValue: true, + }, + WS_PING_INTERVAL: { + envName: 'WS_PING_INTERVAL', + type: 'number', + required: false, + defaultValue: 100000, + }, + WS_POLLING_INTERVAL: { + envName: 'WS_POLLING_INTERVAL', + type: 'number', + required: false, + defaultValue: 500, + }, + WS_RELAY_URL: { + envName: 'WS_RELAY_URL', + type: 'string', + required: false, + defaultValue: 'ws://127.0.0.1:8546', + }, + WS_SAME_SUB_FOR_SAME_EVENT: { + envName: 'WS_SAME_SUB_FOR_SAME_EVENT', + type: 'boolean', + required: false, + defaultValue: true, + }, + WS_SUBSCRIPTION_LIMIT: { + envName: 'WS_SUBSCRIPTION_LIMIT', + type: 'number', + required: false, + defaultValue: 10, + }, +} as const satisfies { [key: string]: ConfigProperty }; // Ensures _CONFIG is read-only and conforms to the ConfigProperty structure + +export type ConfigKey = keyof typeof _CONFIG; + export class GlobalConfig { - public static readonly ENTRIES: Record = { - BATCH_REQUESTS_ENABLED: { - envName: 'BATCH_REQUESTS_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - BATCH_REQUESTS_MAX_SIZE: { - envName: 'BATCH_REQUESTS_MAX_SIZE', - type: 'number', - required: false, - defaultValue: null, - }, - CACHE_MAX: { - envName: 'CACHE_MAX', - type: 'number', - required: false, - defaultValue: null, - }, - CACHE_TTL: { - envName: 'CACHE_TTL', - type: 'number', - required: false, - defaultValue: null, - }, - CHAIN_ID: { - envName: 'CHAIN_ID', - type: 'string', - required: true, - defaultValue: null, - }, - CLIENT_TRANSPORT_SECURITY: { - envName: 'CLIENT_TRANSPORT_SECURITY', - type: 'boolean', - required: false, - defaultValue: null, - }, - CONSENSUS_MAX_EXECUTION_TIME: { - envName: 'CONSENSUS_MAX_EXECUTION_TIME', - type: 'number', - required: false, - defaultValue: null, - }, - CONTRACT_CALL_GAS_LIMIT: { - envName: 'CONTRACT_CALL_GAS_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - CONTRACT_QUERY_TIMEOUT_RETRIES: { - envName: 'CONTRACT_QUERY_TIMEOUT_RETRIES', - type: 'number', - required: false, - defaultValue: null, - }, - DEBUG_API_ENABLED: { - envName: 'DEBUG_API_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - DEFAULT_RATE_LIMIT: { - envName: 'DEFAULT_RATE_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - DEV_MODE: { - envName: 'DEV_MODE', - type: 'boolean', - required: false, - defaultValue: null, - }, - E2E_RELAY_HOST: { - envName: 'E2E_RELAY_HOST', - type: 'string', - required: false, - defaultValue: 'http://localhost:7546', - }, - E2E_SERVER_PORT: { - envName: 'E2E_SERVER_PORT', - type: 'number', - required: false, - defaultValue: null, - }, - ESTIMATE_GAS_THROWS: { - envName: 'ESTIMATE_GAS_THROWS', - type: 'boolean', - required: false, - defaultValue: null, - }, - ETH_BLOCK_NUMBER_CACHE_TTL_MS: { - envName: 'ETH_BLOCK_NUMBER_CACHE_TTL_MS', - type: 'number', - required: false, - defaultValue: null, - }, - ETH_CALL_ACCEPTED_ERRORS: { - envName: 'ETH_CALL_ACCEPTED_ERRORS', - type: 'array', - required: false, - defaultValue: null, - }, - ETH_CALL_CACHE_TTL: { - envName: 'ETH_CALL_CACHE_TTL', - type: 'number', - required: false, - defaultValue: null, - }, - ETH_CALL_CONSENSUS_SELECTORS: { - envName: 'ETH_CALL_CONSENSUS_SELECTORS', - type: 'array', - required: false, - defaultValue: null, - }, - ETH_CALL_DEFAULT_TO_CONSENSUS_NODE: { - envName: 'ETH_CALL_DEFAULT_TO_CONSENSUS_NODE', - type: 'boolean', - required: false, - defaultValue: null, - }, - ETH_FEE_HISTORY_FIXED: { - envName: 'ETH_FEE_HISTORY_FIXED', - type: 'boolean', - required: false, - defaultValue: null, - }, - ETH_GET_BALANCE_CACHE_TTL_MS: { - envName: 'ETH_GET_BALANCE_CACHE_TTL_MS', - type: 'number', - required: false, - defaultValue: null, - }, - ETH_GET_GAS_PRICE_CACHE_TTL_MS: { - envName: 'ETH_GET_GAS_PRICE_CACHE_TTL_MS', - type: 'number', - required: false, - defaultValue: null, - }, - ETH_GET_LOGS_BLOCK_RANGE_LIMIT: { - envName: 'ETH_GET_LOGS_BLOCK_RANGE_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - ETH_GET_TRANSACTION_COUNT_CACHE_TTL: { - envName: 'ETH_GET_TRANSACTION_COUNT_CACHE_TTL', - type: 'number', - required: false, - defaultValue: null, - }, - ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE: { - envName: 'ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE', - type: 'number', - required: false, - defaultValue: null, - }, - HEDERA_SPECIFIC_REVERT_STATUSES: { - envName: 'HEDERA_SPECIFIC_REVERT_STATUSES', - type: 'string', - required: false, - defaultValue: '["WRONG_NONCE", "INVALID_ACCOUNT_ID"]', - }, - FEE_HISTORY_MAX_RESULTS: { - envName: 'FEE_HISTORY_MAX_RESULTS', - type: 'number', - required: false, - defaultValue: null, - }, - FILE_APPEND_CHUNK_SIZE: { - envName: 'FILE_APPEND_CHUNK_SIZE', - type: 'number', - required: false, - defaultValue: null, - }, - FILE_APPEND_MAX_CHUNKS: { - envName: 'FILE_APPEND_MAX_CHUNKS', - type: 'number', - required: false, - defaultValue: null, - }, - FILTER_API_ENABLED: { - envName: 'FILTER_API_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - FILTER_TTL: { - envName: 'FILTER_TTL', - type: 'number', - required: false, - defaultValue: null, - }, - GAS_PRICE_PERCENTAGE_BUFFER: { - envName: 'GAS_PRICE_PERCENTAGE_BUFFER', - type: 'number', - required: false, - defaultValue: null, - }, - GAS_PRICE_TINY_BAR_BUFFER: { - envName: 'GAS_PRICE_TINY_BAR_BUFFER', - type: 'number', - required: false, - defaultValue: null, - }, - GET_RECORD_DEFAULT_TO_CONSENSUS_NODE: { - envName: 'GET_RECORD_DEFAULT_TO_CONSENSUS_NODE', - type: 'boolean', - required: false, - defaultValue: null, - }, - GH_ACCESS_TOKEN: { - envName: 'GH_ACCESS_TOKEN', - type: 'string', - required: false, - defaultValue: null, - }, - GITHUB_PR_NUMBER: { - envName: 'GITHUB_PR_NUMBER', - type: 'string', - required: false, - defaultValue: null, - }, - GITHUB_REPOSITORY: { - envName: 'GITHUB_REPOSITORY', - type: 'string', - required: false, - defaultValue: null, - }, - GITHUB_TOKEN: { - envName: 'GITHUB_TOKEN', - type: 'string', - required: false, - defaultValue: null, - }, - HAPI_CLIENT_DURATION_RESET: { - envName: 'HAPI_CLIENT_DURATION_RESET', - type: 'number', - required: false, - defaultValue: null, - }, - HAPI_CLIENT_ERROR_RESET: { - envName: 'HAPI_CLIENT_ERROR_RESET', - type: 'array', - required: false, - defaultValue: null, - }, - HAPI_CLIENT_TRANSACTION_RESET: { - envName: 'HAPI_CLIENT_TRANSACTION_RESET', - type: 'number', - required: false, - defaultValue: null, - }, - HBAR_RATE_LIMIT_BASIC: { - envName: 'HBAR_RATE_LIMIT_BASIC', - type: 'number', - required: false, - defaultValue: 1_120_000_000, // 11.2 hbar - }, - HBAR_RATE_LIMIT_EXTENDED: { - envName: 'HBAR_RATE_LIMIT_EXTENDED', - type: 'number', - required: false, - defaultValue: 3_200_000_000, // 32 hbar - }, - HBAR_RATE_LIMIT_PRIVILEGED: { - envName: 'HBAR_RATE_LIMIT_PRIVILEGED', - type: 'number', - required: false, - defaultValue: 8_000_000_000, // 80 hbar - }, - HBAR_RATE_LIMIT_DURATION: { - envName: 'HBAR_RATE_LIMIT_DURATION', - type: 'number', - required: false, - defaultValue: 86_400_000, // 24 hours - }, - HBAR_RATE_LIMIT_TINYBAR: { - envName: 'HBAR_RATE_LIMIT_TINYBAR', - type: 'number', - required: false, - defaultValue: 800_000_000_000, // 8000 hbar - }, - HEDERA_NETWORK: { - envName: 'HEDERA_NETWORK', - type: 'string', - required: true, - defaultValue: null, - }, - HBAR_SPENDING_PLANS_CONFIG: { - envName: 'HBAR_SPENDING_PLANS_CONFIG', - type: 'string', - required: false, - defaultValue: 'spendingPlansConfig.json', - }, - INITIAL_BALANCE: { - envName: 'INITIAL_BALANCE', - type: 'number', - required: false, - defaultValue: null, - }, - INPUT_SIZE_LIMIT: { - envName: 'INPUT_SIZE_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - LIMIT_DURATION: { - envName: 'LIMIT_DURATION', - type: 'number', - required: false, - defaultValue: null, - }, - LOCAL_NODE: { - envName: 'LOCAL_NODE', - type: 'boolean', - required: false, - defaultValue: null, - }, - LOG_LEVEL: { - envName: 'LOG_LEVEL', - type: 'string', - required: false, - defaultValue: null, - }, - MAX_BLOCK_RANGE: { - envName: 'MAX_BLOCK_RANGE', - type: 'number', - required: false, - defaultValue: null, - }, - MEMWATCH_ENABLED: { - envName: 'MEMWATCH_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - MIRROR_NODE_AGENT_CACHEABLE_DNS: { - envName: 'MIRROR_NODE_AGENT_CACHEABLE_DNS', - type: 'boolean', - required: false, - defaultValue: null, - }, - MIRROR_NODE_CONTRACT_RESULTS_LOGS_PG_MAX: { - envName: 'MIRROR_NODE_CONTRACT_RESULTS_LOGS_PG_MAX', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_CONTRACT_RESULTS_PG_MAX: { - envName: 'MIRROR_NODE_CONTRACT_RESULTS_PG_MAX', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_HTTP_KEEP_ALIVE: { - envName: 'MIRROR_NODE_HTTP_KEEP_ALIVE', - type: 'boolean', - required: false, - defaultValue: null, - }, - MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS: { - envName: 'MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_HTTP_MAX_SOCKETS: { - envName: 'MIRROR_NODE_HTTP_MAX_SOCKETS', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS: { - envName: 'MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_HTTP_SOCKET_TIMEOUT: { - envName: 'MIRROR_NODE_HTTP_SOCKET_TIMEOUT', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_LIMIT_PARAM: { - envName: 'MIRROR_NODE_LIMIT_PARAM', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_MAX_REDIRECTS: { - envName: 'MIRROR_NODE_MAX_REDIRECTS', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_RETRIES: { - envName: 'MIRROR_NODE_RETRIES', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_RETRIES_DEVMODE: { - envName: 'MIRROR_NODE_RETRIES_DEVMODE', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_RETRY_CODES: { - envName: 'MIRROR_NODE_RETRY_CODES', - type: 'array', - required: false, - defaultValue: null, - }, - MIRROR_NODE_RETRY_DELAY: { - envName: 'MIRROR_NODE_RETRY_DELAY', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_RETRY_DELAY_DEVMODE: { - envName: 'MIRROR_NODE_RETRY_DELAY_DEVMODE', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_REQUEST_RETRY_COUNT: { - envName: 'MIRROR_NODE_REQUEST_RETRY_COUNT', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_TIMEOUT: { - envName: 'MIRROR_NODE_TIMEOUT', - type: 'number', - required: false, - defaultValue: null, - }, - MIRROR_NODE_URL: { - envName: 'MIRROR_NODE_URL', - type: 'string', - required: true, - defaultValue: null, - }, - MIRROR_NODE_URL_HEADER_X_API_KEY: { - envName: 'MIRROR_NODE_URL_HEADER_X_API_KEY', - type: 'array', - required: false, - defaultValue: null, - }, - MIRROR_NODE_URL_WEB3: { - envName: 'MIRROR_NODE_URL_WEB3', - type: 'string', - required: false, - defaultValue: null, - }, - MULTI_SET: { - envName: 'MULTI_SET', - type: 'boolean', - required: false, - defaultValue: null, - }, - // the actual env var in the node process is npm_package_version - npm_package_version: { - envName: 'npm_package_version', - type: 'string', - required: true, - defaultValue: null, - }, - OPERATOR_ID_ETH_SENDRAWTRANSACTION: { - envName: 'OPERATOR_ID_ETH_SENDRAWTRANSACTION', - type: 'string', - required: false, - defaultValue: null, - }, - OPERATOR_ID_MAIN: { - envName: 'OPERATOR_ID_MAIN', - type: 'string', - required: true, - defaultValue: null, - }, - OPERATOR_KEY_ETH_SENDRAWTRANSACTION: { - envName: 'OPERATOR_KEY_ETH_SENDRAWTRANSACTION', - type: 'string', - required: false, - defaultValue: null, - }, - OPERATOR_KEY_FORMAT: { - envName: 'OPERATOR_KEY_FORMAT', - type: 'string', - required: false, - defaultValue: null, - }, - OPERATOR_KEY_MAIN: { - envName: 'OPERATOR_KEY_MAIN', - type: 'string', - required: true, - defaultValue: null, - }, - RATE_LIMIT_DISABLED: { - envName: 'RATE_LIMIT_DISABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - REDIS_ENABLED: { - envName: 'REDIS_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - REDIS_RECONNECT_DELAY_MS: { - envName: 'REDIS_RECONNECT_DELAY_MS', - type: 'number', - required: false, - defaultValue: null, - }, - REDIS_URL: { - envName: 'REDIS_URL', - type: 'string', - required: false, - defaultValue: 'redis://127.0.0.1:6379', - }, - REQUEST_ID_IS_OPTIONAL: { - envName: 'REQUEST_ID_IS_OPTIONAL', - type: 'boolean', - required: false, - defaultValue: null, - }, - SDK_REQUEST_TIMEOUT: { - envName: 'SDK_REQUEST_TIMEOUT', - type: 'number', - required: false, - defaultValue: null, - }, - SEND_RAW_TRANSACTION_SIZE_LIMIT: { - envName: 'SEND_RAW_TRANSACTION_SIZE_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - SERVER_PORT: { - envName: 'SERVER_PORT', - type: 'number', - required: false, - defaultValue: 7546, - }, - SERVER_REQUEST_TIMEOUT_MS: { - envName: 'SERVER_REQUEST_TIMEOUT_MS', - type: 'number', - required: false, - defaultValue: null, - }, - SUBSCRIPTIONS_ENABLED: { - envName: 'SUBSCRIPTIONS_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - TEST: { - envName: 'TEST', - type: 'boolean', - required: false, - defaultValue: null, - }, - TEST_GAS_PRICE_DEVIATION: { - envName: 'TEST_GAS_PRICE_DEVIATION', - type: 'number', - required: false, - defaultValue: null, - }, - TEST_INITIAL_ACCOUNT_STARTING_BALANCE: { - envName: 'TEST_INITIAL_ACCOUNT_STARTING_BALANCE', - type: 'number', - required: false, - defaultValue: null, - }, - TEST_TRANSACTION_RECORD_COST_TOLERANCE: { - envName: 'TEST_TRANSACTION_RECORD_COST_TOLERANCE', - type: 'number', - required: false, - defaultValue: null, - }, - TEST_WS_SERVER: { - envName: 'TEST_WS_SERVER', - type: 'boolean', - required: false, - defaultValue: null, - }, - TIER_1_RATE_LIMIT: { - envName: 'TIER_1_RATE_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - TIER_2_RATE_LIMIT: { - envName: 'TIER_2_RATE_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - TIER_3_RATE_LIMIT: { - envName: 'TIER_3_RATE_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - TX_DEFAULT_GAS: { - envName: 'TX_DEFAULT_GAS', - type: 'number', - required: false, - defaultValue: null, - }, - USE_ASYNC_TX_PROCESSING: { - envName: 'USE_ASYNC_TX_PROCESSING', - type: 'boolean', - required: false, - defaultValue: false, - }, - WEB_SOCKET_HTTP_PORT: { - envName: 'WEB_SOCKET_HTTP_PORT', - type: 'number', - required: false, - defaultValue: 8547, - }, - WEB_SOCKET_PORT: { - envName: 'WEB_SOCKET_PORT', - type: 'number', - required: false, - defaultValue: 8546, - }, - WRITE_SNAPSHOT_ON_MEMORY_LEAK: { - envName: 'WRITE_SNAPSHOT_ON_MEMORY_LEAK', - type: 'boolean', - required: false, - defaultValue: null, - }, - WS_BATCH_REQUESTS_ENABLED: { - envName: 'WS_BATCH_REQUESTS_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - WS_BATCH_REQUESTS_MAX_SIZE: { - envName: 'WS_BATCH_REQUESTS_MAX_SIZE', - type: 'number', - required: false, - defaultValue: null, - }, - WS_CACHE_TTL: { - envName: 'WS_CACHE_TTL', - type: 'number', - required: false, - defaultValue: null, - }, - WS_CONNECTION_LIMIT: { - envName: 'WS_CONNECTION_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - WS_CONNECTION_LIMIT_PER_IP: { - envName: 'WS_CONNECTION_LIMIT_PER_IP', - type: 'number', - required: false, - defaultValue: null, - }, - WS_MAX_INACTIVITY_TTL: { - envName: 'WS_MAX_INACTIVITY_TTL', - type: 'number', - required: false, - defaultValue: null, - }, - WS_MULTIPLE_ADDRESSES_ENABLED: { - envName: 'WS_MULTIPLE_ADDRESSES_ENABLED', - type: 'boolean', - required: false, - defaultValue: null, - }, - WS_NEW_HEADS_ENABLED: { - envName: 'WS_NEW_HEADS_ENABLED', - type: 'boolean', - required: false, - defaultValue: true, - }, - WS_PING_INTERVAL: { - envName: 'WS_PING_INTERVAL', - type: 'number', - required: false, - defaultValue: null, - }, - WS_POLLING_INTERVAL: { - envName: 'WS_POLLING_INTERVAL', - type: 'number', - required: false, - defaultValue: null, - }, - WS_RELAY_URL: { - envName: 'WS_RELAY_URL', - type: 'string', - required: false, - defaultValue: 'ws://127.0.0.1:8546', - }, - WS_SAME_SUB_FOR_SAME_EVENT: { - envName: 'WS_SAME_SUB_FOR_SAME_EVENT', - type: 'boolean', - required: false, - defaultValue: null, - }, - WS_SUBSCRIPTION_LIMIT: { - envName: 'WS_SUBSCRIPTION_LIMIT', - type: 'number', - required: false, - defaultValue: null, - }, - }; + public static readonly ENTRIES: Record = _CONFIG; } diff --git a/packages/config-service/src/services/index.ts b/packages/config-service/src/services/index.ts index 1ed30abaef..2a4580e81a 100644 --- a/packages/config-service/src/services/index.ts +++ b/packages/config-service/src/services/index.ts @@ -22,6 +22,8 @@ import dotenv from 'dotenv'; import findConfig from 'find-config'; import pino from 'pino'; +import type { ConfigKey, GetTypeOfConfigKey } from './globalConfig'; +import { GlobalConfig } from './globalConfig'; import { LoggerService } from './loggerService'; import { ValidationService } from './validationService'; @@ -93,11 +95,35 @@ export class ConfigService { } /** - * Get an env var by name - * @param name string - * @returns string | undefined + * Retrieves the value of a specified configuration property using its key name. + * + * The method incorporates validation to ensure required configuration values are provided. + * + * **Note:** The validations in this method, in addition to the `ValidationService.startUp(process.env)` in the constructor, are crucial + * as this method is frequently invoked in testing environments where configuration values might be dynamically + * overridden. Additionally, since this method is the most exposed method across different packages, serving as the + * main gateway for accessing configurations, these validations help strengthen security and prevent undefined + * behavior in both production and testing scenarios. + * + * For the CHAIN_ID key, the value is converted to a hexadecimal format prefixed with '0x'. + * + * @param name - The configuration key to retrieve. + * @typeParam K - The specific type parameter representing the ConfigKey. + * @returns The value associated with the specified key, or the default value from its GlobalConfig entry, properly typed based on the key's configuration. + * @throws Error if a required configuration value is missing. */ - public static get(name: string): string | number | boolean | null | undefined { - return this.getInstance().envs[name]; + public static get(name: K): GetTypeOfConfigKey { + const configEntry = GlobalConfig.ENTRIES[name]; + let value = this.getInstance().envs[name] == undefined ? configEntry?.defaultValue : this.getInstance().envs[name]; + + if (value == undefined && configEntry?.required) { + throw new Error(`Configuration error: ${name} is a mandatory configuration for relay operation.`); + } + + if (name === 'CHAIN_ID' && value !== undefined) { + value = `0x${Number(value).toString(16)}`; + } + + return value as GetTypeOfConfigKey; } } diff --git a/packages/config-service/src/services/validationService.ts b/packages/config-service/src/services/validationService.ts index 738fc36391..38519971a9 100644 --- a/packages/config-service/src/services/validationService.ts +++ b/packages/config-service/src/services/validationService.ts @@ -30,26 +30,33 @@ export class ValidationService { Object.entries(GlobalConfig.ENTRIES).forEach(([entryName, entryInfo]) => { if (entryInfo.required) { if (!envs.hasOwnProperty(entryName)) { - throw new Error(`${entryName} is a mandatory and the relay cannot operate without its value.`); + throw new Error(`Configuration error: ${entryName} is a mandatory configuration for relay operation.`); } if (entryInfo.type === 'number' && isNaN(Number(envs[entryName]))) { - throw new Error(`${entryName} must be a valid number.`); + throw new Error(`Configuration error: ${entryName} must be a valid number.`); } } }); } /** - * Transform string env variables to the proper formats (number/boolean/string) - * @param envs + * Transform string environment variables to their proper types based on GlobalConfig.ENTRIES. + * For each entry: + * - If the env var is missing but has a default value, use the default + * - For 'number' type, converts to Number + * - For 'boolean' type, converts 'true' string to true boolean + * - For 'string' and 'array' types, keeps as string + * + * @param envs - Dictionary of environment variables and their string values + * @returns Dictionary with environment variables cast to their proper types */ static typeCasting(envs: NodeJS.Dict): NodeJS.Dict { const typeCastedEnvs: NodeJS.Dict = {}; Object.entries(GlobalConfig.ENTRIES).forEach(([entryName, entryInfo]) => { if (!envs.hasOwnProperty(entryName)) { - if (entryInfo.defaultValue) { + if (entryInfo.defaultValue != null) { typeCastedEnvs[entryName] = entryInfo.defaultValue; } return; diff --git a/packages/config-service/tests/src/services/configService.spec.ts b/packages/config-service/tests/src/services/configService.spec.ts index ab7e062d7b..4c43b263d5 100644 --- a/packages/config-service/tests/src/services/configService.spec.ts +++ b/packages/config-service/tests/src/services/configService.spec.ts @@ -20,7 +20,9 @@ import chai, { expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; + import { ConfigService } from '../../../src/services'; +import { type ConfigKey, GlobalConfig } from '../../../src/services/globalConfig'; chai.use(chaiAsPromised); @@ -50,13 +52,76 @@ describe('ConfigService tests', async function () { it('should be able to get existing env var', async () => { const res = ConfigService.get('CHAIN_ID'); - expect(res).to.equal('0x12a'); }); it('should return undefined for non-existing variable', async () => { - const res = ConfigService.get('NON_EXISTING_VAR'); - + const res = ConfigService.get('NON_EXISTING_VAR' as ConfigKey); expect(res).to.equal(undefined); }); + + it('should return the default value for configurations not set in process.env', async () => { + const targetKey = 'FILE_APPEND_MAX_CHUNKS'; + const envValue = process.env[targetKey]; + + // ensure the key is not listed in env + expect(envValue).to.be.undefined; + + const expectedDefaultValue = GlobalConfig.ENTRIES[targetKey].defaultValue; + + const res = ConfigService.get(targetKey); + expect(res).to.equal(expectedDefaultValue); + }); + + it('should infer the explicit type for configuration which is either required or has a valid defaultValue', () => { + const targetKeys = [ + 'FILE_APPEND_MAX_CHUNKS', + 'GET_RECORD_DEFAULT_TO_CONSENSUS_NODE', + 'E2E_RELAY_HOST', + 'ETH_CALL_ACCEPTED_ERRORS', + ] as ConfigKey[]; + + targetKeys.forEach((targetKey) => { + const result = ConfigService.get(targetKey); + const expectedTypeString = GlobalConfig.ENTRIES[targetKey].type; + + switch (expectedTypeString) { + case 'number': + expect(typeof result === 'number').to.be.true; + break; + case 'boolean': + expect(typeof result === 'boolean').to.be.true; + break; + case 'string': + expect(typeof result === 'string').to.be.true; + break; + } + }); + }); + + it('Should always convert CHAIN_ID to a hexadecimal string, regardless of input value type.', async () => { + const originalEnv = process.env; + + const testChainId = (input: string, expected: string) => { + process.env = { ...originalEnv, CHAIN_ID: input }; + // Reset the ConfigService singleton instance to force a new initialization + // This is necessary because ConfigService caches the env values when first instantiated, + // so we need to clear that cache to test with our new CHAIN_ID value + // @ts-ignore - accessing private property for testing + delete ConfigService.instance; + expect(ConfigService.get('CHAIN_ID')).to.equal(expected); + }; + + try { + // Test cases + testChainId('298', '0x12a'); // decimal number + testChainId('0x12a', '0x12a'); // hexadecimal with prefix + testChainId('1000000', '0xf4240'); // larger number + testChainId('0xhedera', '0xNaN'); // invalid number + } finally { + process.env = originalEnv; + // @ts-ignore - accessing private property for testing + delete ConfigService.instance; + } + }); }); diff --git a/packages/config-service/tests/src/services/loggerService.spec.ts b/packages/config-service/tests/src/services/loggerService.spec.ts index e33faa0f14..dc311f687c 100644 --- a/packages/config-service/tests/src/services/loggerService.spec.ts +++ b/packages/config-service/tests/src/services/loggerService.spec.ts @@ -47,7 +47,7 @@ describe('LoggerService tests', async function () { }); it('should be able to return plain information', async () => { - const envName = GlobalConfig.ENTRIES.CHAIN_ID.envName; + const envName = 'CHAIN_ID'; const res = ConfigService.get(envName); expect(LoggerService.maskUpEnv(envName, res)).to.equal(`${envName} = ${res}`); diff --git a/packages/config-service/tests/src/services/validationService.spec.ts b/packages/config-service/tests/src/services/validationService.spec.ts index 9fd5671ae0..1dd25fc63d 100644 --- a/packages/config-service/tests/src/services/validationService.spec.ts +++ b/packages/config-service/tests/src/services/validationService.spec.ts @@ -41,7 +41,7 @@ describe('ValidationService tests', async function () { it('should fail fast if mandatory env is not passed', async () => { expect(() => ValidationService.startUp({})).to.throw( - 'CHAIN_ID is a mandatory and the relay cannot operate without its value.', + 'Configuration error: CHAIN_ID is a mandatory configuration for relay operation.', ); }); @@ -77,7 +77,7 @@ describe('ValidationService tests', async function () { ValidationService.startUp({ ...mandatoryStartUpFields, }), - ).to.throw('npm_package_version is a mandatory and the relay cannot operate without its value.'); + ).to.throw('Configuration error: npm_package_version is a mandatory configuration for relay operation.'); }); }); @@ -92,8 +92,8 @@ describe('ValidationService tests', async function () { it('should skip adding value if it is missing and there is no default value set', async () => { const castedEnvs = ValidationService.typeCasting({}); - expect(castedEnvs).to.not.haveOwnProperty(GlobalConfig.ENTRIES.FILTER_TTL.envName); - expect(castedEnvs[GlobalConfig.ENTRIES.FILTER_TTL.envName]).to.be.undefined; + expect(castedEnvs).to.not.haveOwnProperty(GlobalConfig.ENTRIES.GH_ACCESS_TOKEN.envName); + expect(castedEnvs[GlobalConfig.ENTRIES.GH_ACCESS_TOKEN.envName]).to.be.undefined; }); it('should to cast string type', async () => { diff --git a/packages/relay/src/lib/clients/cache/localLRUCache.ts b/packages/relay/src/lib/clients/cache/localLRUCache.ts index 5ca79dfd50..9d4625dd59 100644 --- a/packages/relay/src/lib/clients/cache/localLRUCache.ts +++ b/packages/relay/src/lib/clients/cache/localLRUCache.ts @@ -21,7 +21,6 @@ import { Logger } from 'pino'; import { Gauge, Registry } from 'prom-client'; import { ICacheClient } from './ICacheClient'; -import constants from '../../constants'; import LRUCache, { LimitedByCount, LimitedByTTL } from 'lru-cache'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { RequestDetails } from '../../types'; @@ -40,11 +39,9 @@ export class LocalLRUCache implements ICacheClient { */ private readonly options: LimitedByCount & LimitedByTTL = { // The maximum number (or size) of items that remain in the cache (assuming no TTL pruning or explicit deletions). - // @ts-ignore - max: Number.parseInt(ConfigService.get('CACHE_MAX') ?? constants.CACHE_MAX.toString()), + max: ConfigService.get('CACHE_MAX'), // Max time to live in ms, for items before they are considered stale. - // @ts-ignore - ttl: Number.parseInt(ConfigService.get('CACHE_TTL') ?? constants.CACHE_TTL.ONE_HOUR.toString()), + ttl: ConfigService.get('CACHE_TTL'), }; /** diff --git a/packages/relay/src/lib/clients/cache/redisCache.ts b/packages/relay/src/lib/clients/cache/redisCache.ts index f59b40f2ab..32cf4d74d3 100644 --- a/packages/relay/src/lib/clients/cache/redisCache.ts +++ b/packages/relay/src/lib/clients/cache/redisCache.ts @@ -40,8 +40,7 @@ export class RedisCache implements IRedisCacheClient { */ private readonly options = { // Max time to live in ms, for items before they are considered stale. - // @ts-ignore - ttl: Number.parseInt(ConfigService.get('CACHE_TTL') ?? constants.CACHE_TTL.ONE_HOUR.toString()), + ttl: ConfigService.get('CACHE_TTL'), }; /** @@ -79,8 +78,7 @@ export class RedisCache implements IRedisCacheClient { this.register = register; const redisUrl = ConfigService.get('REDIS_URL')!; - // @ts-ignore - const reconnectDelay = parseInt(ConfigService.get('REDIS_RECONNECT_DELAY_MS') || '1000'); + const reconnectDelay = ConfigService.get('REDIS_RECONNECT_DELAY_MS'); this.client = createClient({ // @ts-ignore url: redisUrl, diff --git a/packages/relay/src/lib/clients/mirrorNodeClient.ts b/packages/relay/src/lib/clients/mirrorNodeClient.ts index 3baf4c0a26..fb8b429f48 100644 --- a/packages/relay/src/lib/clients/mirrorNodeClient.ts +++ b/packages/relay/src/lib/clients/mirrorNodeClient.ts @@ -80,14 +80,8 @@ export class MirrorNodeClient { private static readonly GET_CONTRACT_RESULT_LOGS_BY_ADDRESS_ENDPOINT = `contracts/${MirrorNodeClient.ADDRESS_PLACEHOLDER}/results/logs`; private static readonly GET_CONTRACT_RESULTS_DETAILS_BY_CONTRACT_ID_ENDPOINT = `contracts/${MirrorNodeClient.CONTRACT_ID_PLACEHOLDER}/results/${MirrorNodeClient.TIMESTAMP_PLACEHOLDER}`; private static readonly GET_CONTRACT_RESULTS_DETAILS_BY_ADDRESS_AND_TIMESTAMP_ENDPOINT = `contracts/${MirrorNodeClient.ADDRESS_PLACEHOLDER}/results/${MirrorNodeClient.TIMESTAMP_PLACEHOLDER}`; - private readonly MIRROR_NODE_RETRY_DELAY = parseNumericEnvVar( - 'MIRROR_NODE_RETRY_DELAY', - 'MIRROR_NODE_RETRY_DELAY_DEFAULT', - ); - private readonly MIRROR_NODE_REQUEST_RETRY_COUNT = parseNumericEnvVar( - 'MIRROR_NODE_REQUEST_RETRY_COUNT', - 'MIRROR_NODE_REQUEST_RETRY_COUNT_DEFAULT', - ); + private readonly MIRROR_NODE_RETRY_DELAY = ConfigService.get('MIRROR_NODE_RETRY_DELAY'); + private readonly MIRROR_NODE_REQUEST_RETRY_COUNT = ConfigService.get('MIRROR_NODE_REQUEST_RETRY_COUNT'); static acceptedErrorStatusesResponsePerRequestPathMap: Map> = new Map([ [MirrorNodeClient.GET_ACCOUNTS_BY_ID_ENDPOINT, [404]], @@ -161,47 +155,29 @@ export class MirrorNodeClient { static readonly EVM_ADDRESS_REGEX: RegExp = /\/accounts\/([\d\.]+)/; - public static readonly mirrorNodeContractResultsPageMax = parseInt( - // @ts-ignore - ConfigService.get('MIRROR_NODE_CONTRACT_RESULTS_PG_MAX') || 25, + public static readonly mirrorNodeContractResultsPageMax = ConfigService.get('MIRROR_NODE_CONTRACT_RESULTS_PG_MAX'); + public static readonly mirrorNodeContractResultsLogsPageMax = ConfigService.get( + 'MIRROR_NODE_CONTRACT_RESULTS_LOGS_PG_MAX', ); - public static readonly mirrorNodeContractResultsLogsPageMax = - // @ts-ignore - parseInt(ConfigService.get('MIRROR_NODE_CONTRACT_RESULTS_LOGS_PG_MAX') || 200); protected createAxiosClient(baseUrl: string): AxiosInstance { // defualt values for axios clients to mirror node - // @ts-ignore - const mirrorNodeTimeout = parseInt(ConfigService.get('MIRROR_NODE_TIMEOUT') || '10000'); - // @ts-ignore - const mirrorNodeMaxRedirects = parseInt(ConfigService.get('MIRROR_NODE_MAX_REDIRECTS') || '5'); + const mirrorNodeTimeout = ConfigService.get('MIRROR_NODE_TIMEOUT'); + const mirrorNodeMaxRedirects = ConfigService.get('MIRROR_NODE_MAX_REDIRECTS'); const mirrorNodeHttpKeepAlive = ConfigService.get('MIRROR_NODE_HTTP_KEEP_ALIVE'); - // @ts-ignore - const mirrorNodeHttpKeepAliveMsecs = parseInt(ConfigService.get('MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS') || '1000'); - // @ts-ignore - const mirrorNodeHttpMaxSockets = parseInt(ConfigService.get('MIRROR_NODE_HTTP_MAX_SOCKETS') || '300'); - // @ts-ignore - const mirrorNodeHttpMaxTotalSockets = parseInt(ConfigService.get('MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS') || '300'); - // @ts-ignore - const mirrorNodeHttpSocketTimeout = parseInt(ConfigService.get('MIRROR_NODE_HTTP_SOCKET_TIMEOUT') || '60000'); + const mirrorNodeHttpKeepAliveMsecs = ConfigService.get('MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS'); + const mirrorNodeHttpMaxSockets = ConfigService.get('MIRROR_NODE_HTTP_MAX_SOCKETS'); + const mirrorNodeHttpMaxTotalSockets = ConfigService.get('MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS'); + const mirrorNodeHttpSocketTimeout = ConfigService.get('MIRROR_NODE_HTTP_SOCKET_TIMEOUT'); const isDevMode = ConfigService.get('DEV_MODE'); - // @ts-ignore - const mirrorNodeRetries = parseInt(ConfigService.get('MIRROR_NODE_RETRIES') || '0'); // we are in the process of deprecating this feature - // @ts-ignore - const mirrorNodeRetriesDevMode = parseInt(ConfigService.get('MIRROR_NODE_RETRIES_DEVMODE') || '5'); + const mirrorNodeRetries = ConfigService.get('MIRROR_NODE_RETRIES'); // we are in the process of deprecating this feature + const mirrorNodeRetriesDevMode = ConfigService.get('MIRROR_NODE_RETRIES_DEVMODE'); const mirrorNodeRetryDelay = this.MIRROR_NODE_RETRY_DELAY; - // @ts-ignore - const mirrorNodeRetryDelayDevMode = parseInt(ConfigService.get('MIRROR_NODE_RETRY_DELAY_DEVMODE') || '200'); - const mirrorNodeRetryErrorCodes = ConfigService.get('MIRROR_NODE_RETRY_CODES') - ? // @ts-ignore - JSON.parse(ConfigService.get('MIRROR_NODE_RETRY_CODES')) - : []; // we are in the process of deprecating this feature - // by default will be true, unless explicitly set to false. - // @ts-ignore + const mirrorNodeRetryDelayDevMode = ConfigService.get('MIRROR_NODE_RETRY_DELAY_DEVMODE'); + const mirrorNodeRetryErrorCodes = JSON.parse(ConfigService.get('MIRROR_NODE_RETRY_CODES')); // we are in the process of deprecating this feature by default will be true, unless explicitly set to false. const useCacheableDnsLookup: boolean = ConfigService.get('MIRROR_NODE_AGENT_CACHEABLE_DNS'); const httpAgent = new http.Agent({ - // @ts-ignore keepAlive: mirrorNodeHttpKeepAlive, keepAliveMsecs: mirrorNodeHttpKeepAliveMsecs, maxSockets: mirrorNodeHttpMaxSockets, @@ -258,6 +234,7 @@ export class MirrorNodeClient { return delay; }, retryCondition: (error) => { + // @ts-ignore return !error?.response?.status || mirrorNodeRetryErrorCodes.includes(error?.response?.status); }, shouldResetTimeout: true, @@ -313,11 +290,11 @@ export class MirrorNodeClient { this.cacheService = cacheService; // set up eth call accepted error codes. - if (ConfigService.get('ETH_CALL_ACCEPTED_ERRORS')) { + const parsedAcceptedError = JSON.parse(ConfigService.get('ETH_CALL_ACCEPTED_ERRORS')); + if (parsedAcceptedError.length != 0) { MirrorNodeClient.acceptedErrorStatusesResponsePerRequestPathMap.set( MirrorNodeClient.CONTRACT_CALL_ENDPOINT, - // @ts-ignore - JSON.parse(ConfigService.get('ETH_CALL_ACCEPTED_ERRORS')), + parsedAcceptedError, ); } } @@ -1326,8 +1303,7 @@ export class MirrorNodeClient { this.setQueryParam(queryParamObject, 'limit', limitOrderParams.limit); this.setQueryParam(queryParamObject, 'order', limitOrderParams.order); } else { - // @ts-ignore - this.setQueryParam(queryParamObject, 'limit', parseInt(ConfigService.get('MIRROR_NODE_LIMIT_PARAM') || '100')); + this.setQueryParam(queryParamObject, 'limit', ConfigService.get('MIRROR_NODE_LIMIT_PARAM')); this.setQueryParam(queryParamObject, 'order', constants.ORDER.ASC); } } diff --git a/packages/relay/src/lib/clients/sdkClient.ts b/packages/relay/src/lib/clients/sdkClient.ts index 2f7572526d..505a3fd944 100644 --- a/packages/relay/src/lib/clients/sdkClient.ts +++ b/packages/relay/src/lib/clients/sdkClient.ts @@ -140,18 +140,16 @@ export class SDKClient { ) { this.clientMain = clientMain; - if (ConfigService.get('CONSENSUS_MAX_EXECUTION_TIME')) { - // sets the maximum time in ms for the SDK to wait when submitting - // a transaction/query before throwing a TIMEOUT error - this.clientMain = clientMain.setMaxExecutionTime(Number(ConfigService.get('CONSENSUS_MAX_EXECUTION_TIME'))); - } + // sets the maximum time in ms for the SDK to wait when submitting + // a transaction/query before throwing a TIMEOUT error + this.clientMain = clientMain.setMaxExecutionTime(ConfigService.get('CONSENSUS_MAX_EXECUTION_TIME')); this.logger = logger; this.cacheService = cacheService; this.eventEmitter = eventEmitter; this.hbarLimitService = hbarLimitService; - this.maxChunks = Number(ConfigService.get('FILE_APPEND_MAX_CHUNKS')) || 20; - this.fileAppendChunkSize = Number(ConfigService.get('FILE_APPEND_CHUNK_SIZE')) || 5120; + this.maxChunks = ConfigService.get('FILE_APPEND_MAX_CHUNKS'); + this.fileAppendChunkSize = ConfigService.get('FILE_APPEND_CHUNK_SIZE'); } /** @@ -519,8 +517,7 @@ export class SDKClient { ): Promise { let retries = 0; let resp; - // @ts-ignore - while (parseInt(ConfigService.get('CONTRACT_QUERY_TIMEOUT_RETRIES') || '1') > retries) { + while (ConfigService.get('CONTRACT_QUERY_TIMEOUT_RETRIES') > retries) { try { resp = await this.submitContractCallQuery(to, data, gas, from, callerName, requestDetails); return resp; diff --git a/packages/relay/src/lib/config/hbarSpendingPlanConfigService.ts b/packages/relay/src/lib/config/hbarSpendingPlanConfigService.ts index bbb6bd4b5b..57beb8c632 100644 --- a/packages/relay/src/lib/config/hbarSpendingPlanConfigService.ts +++ b/packages/relay/src/lib/config/hbarSpendingPlanConfigService.ts @@ -129,7 +129,7 @@ export class HbarSpendingPlanConfigService { * @private */ private static loadSpendingPlansConfig(logger: Logger): SpendingPlanConfig[] { - const spendingPlanConfig = ConfigService.get('HBAR_SPENDING_PLANS_CONFIG') as string; + const spendingPlanConfig = ConfigService.get('HBAR_SPENDING_PLANS_CONFIG'); if (!spendingPlanConfig) { if (logger.isLevelEnabled('trace')) { diff --git a/packages/relay/src/lib/constants.ts b/packages/relay/src/lib/constants.ts index 6c33ef4e72..6d01783b5b 100644 --- a/packages/relay/src/lib/constants.ts +++ b/packages/relay/src/lib/constants.ts @@ -1,8 +1,8 @@ -/* - +/*- * * Hedera JSON RPC Relay * - * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * Copyright (C) 2025 Hedera Hashgraph, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,18 +87,10 @@ export default { HBAR_TO_TINYBAR_COEF: 100_000_000, TINYBAR_TO_WEIBAR_COEF: 10_000_000_000, TOTAL_SUPPLY_TINYBARS: 5_000_000_000_000_000_000, - // 131072 bytes are 128kbytes - SEND_RAW_TRANSACTION_SIZE_LIMIT: ConfigService.get('SEND_RAW_TRANSACTION_SIZE_LIMIT') - ? // @ts-ignore - parseInt(ConfigService.get('SEND_RAW_TRANSACTION_SIZE_LIMIT')) - : 131072, - CACHE_KEY, CACHE_TTL, - CACHE_MAX: 1000, DEFAULT_TINY_BAR_GAS: 72, // (853454 / 1000) * (1 / 12) ETH_FUNCTIONALITY_CODE: 84, - DEFAULT_ETH_GET_LOGS_BLOCK_RANGE_LIMIT: 1000, EXCHANGE_RATE_FILE_ID: '0.0.112', FEE_SCHEDULE_FILE_ID: '0.0.111', @@ -145,7 +137,6 @@ export default { // block ranges MAX_BLOCK_RANGE: 5, - ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE: 1000, BLOCK_HASH_REGEX: '^0[xX][a-fA-F0-9]', DEFAULT_RATE_LIMIT: { @@ -155,29 +146,19 @@ export default { DURATION: 60000, }, - // @ts-ignore - HBAR_RATE_LIMIT_DURATION: parseInt(ConfigService.get('HBAR_RATE_LIMIT_DURATION')), - // @ts-ignore - // The logical OR operator || returns the first truthy value and 0 is falsy. - // The nullish coalescing operator ?? falls back to the default value when the left-hand operand is null or undefined, not when it's 0 or any other falsy value. + HBAR_RATE_LIMIT_DURATION: ConfigService.get('HBAR_RATE_LIMIT_DURATION'), HBAR_RATE_LIMIT_TOTAL: BigNumber(ConfigService.get('HBAR_RATE_LIMIT_TINYBAR')), - // @ts-ignore HBAR_RATE_LIMIT_BASIC: BigNumber(ConfigService.get('HBAR_RATE_LIMIT_BASIC')), - // @ts-ignore HBAR_RATE_LIMIT_EXTENDED: BigNumber(ConfigService.get('HBAR_RATE_LIMIT_EXTENDED')), - // @ts-ignore HBAR_RATE_LIMIT_PRIVILEGED: BigNumber(ConfigService.get('HBAR_RATE_LIMIT_PRIVILEGED')), - // @ts-ignore - GAS_PRICE_TINY_BAR_BUFFER: parseInt(ConfigService.get('GAS_PRICE_TINY_BAR_BUFFER') || '10000000000'), - WEB_SOCKET_PORT: ConfigService.get('WEB_SOCKET_PORT') || 8546, - WEB_SOCKET_HTTP_PORT: ConfigService.get('WEB_SOCKET_HTTP_PORT') || 8547, + GAS_PRICE_TINY_BAR_BUFFER: ConfigService.get('GAS_PRICE_TINY_BAR_BUFFER'), + WEB_SOCKET_PORT: ConfigService.get('WEB_SOCKET_PORT'), + WEB_SOCKET_HTTP_PORT: ConfigService.get('WEB_SOCKET_HTTP_PORT'), - RELAY_PORT: ConfigService.get('SERVER_PORT') || 7546, + RELAY_PORT: ConfigService.get('SERVER_PORT'), RELAY_HOST: ConfigService.get('SERVER_HOST') || 'localhost', FUNCTION_SELECTOR_CHAR_LENGTH: 10, - MIRROR_NODE_RETRY_DELAY_DEFAULT: 2000, - MIRROR_NODE_REQUEST_RETRY_COUNT_DEFAULT: 10, BASE_HEX_REGEX: '^0[xX][a-fA-F0-9]', TRANSACTION_RESULT_STATUS: { @@ -195,8 +176,7 @@ export default { LOG: 'log', PENDING_TRANSACTION: 'pendingTransaction', }, - // @ts-ignore - TTL: parseInt(ConfigService.get('FILTER_TTL') || '300000'), // default is 5 minutes + TTL: ConfigService.get('FILTER_TTL'), }, METHODS: { diff --git a/packages/relay/src/lib/eth.ts b/packages/relay/src/lib/eth.ts index 3c420bb59f..5226d05c91 100644 --- a/packages/relay/src/lib/eth.ts +++ b/packages/relay/src/lib/eth.ts @@ -159,17 +159,12 @@ export class EthImpl implements Eth { ); private readonly maxBlockRange = parseNumericEnvVar('MAX_BLOCK_RANGE', 'MAX_BLOCK_RANGE'); private readonly contractCallGasLimit = parseNumericEnvVar('CONTRACT_CALL_GAS_LIMIT', 'CONTRACT_CALL_GAS_LIMIT'); - private readonly ethGetTransactionCountMaxBlockRange = parseNumericEnvVar( - 'ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE', - 'ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE', - ); + private readonly ethGetTransactionCountMaxBlockRange = ConfigService.get('ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE'); private readonly ethGetTransactionCountCacheTtl = parseNumericEnvVar( 'ETH_GET_TRANSACTION_COUNT_CACHE_TTL', 'ETH_GET_TRANSACTION_COUNT_CACHE_TTL', ); - private readonly estimateGasThrows = ConfigService.get('ESTIMATE_GAS_THROWS') - ? ConfigService.get('ESTIMATE_GAS_THROWS') - : true; + private readonly estimateGasThrows = ConfigService.get('ESTIMATE_GAS_THROWS'); private readonly ethGasPRiceCacheTtlMs = parseNumericEnvVar( 'ETH_GET_GAS_PRICE_CACHE_TTL_MS', @@ -183,9 +178,9 @@ export class EthImpl implements Eth { */ private readonly options = { //The maximum number (or size) of items that remain in the cache (assuming no TTL pruning or explicit deletions). - max: constants.CACHE_MAX, + max: ConfigService.get('CACHE_MAX'), // Max time to live in ms, for items before they are considered stale. - ttl: constants.CACHE_TTL.ONE_HOUR, + ttl: ConfigService.get('CACHE_TTL'), }; /** @@ -317,8 +312,7 @@ export class EthImpl implements Eth { } private getEthFeeHistoryFixedFee(): boolean { - // @ts-ignore - return ConfigService.get('ETH_FEE_HISTORY_FIXED') ?? true; + return ConfigService.get('ETH_FEE_HISTORY_FIXED'); } /** @@ -1810,7 +1804,7 @@ export class EthImpl implements Eth { * the transaction hash is calculated and returned immediately after passing all prechecks. * All transaction processing logic is then handled asynchronously in the background. */ - const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING') as boolean; + const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING'); if (useAsyncTxProcessing) { this.sendRawTransactionProcessor(transactionBuffer, parsedTx, networkGasPriceInWeiBars, requestDetails); return Utils.computeTransactionHash(transactionBuffer); @@ -1874,8 +1868,7 @@ export class EthImpl implements Eth { // When eth_call is invoked with a selector listed in specialSelectors, it will be routed through the consensus node, regardless of ETH_CALL_DEFAULT_TO_CONSENSUS_NODE. // note: this feature is a workaround for when a feature is supported by consensus node but not yet by mirror node. // Follow this ticket https://github.com/hashgraph/hedera-json-rpc-relay/issues/2984 to revisit and remove special selectors. - // @ts-ignore - const specialSelectors: string[] = JSON.parse(ConfigService.get('ETH_CALL_CONSENSUS_SELECTORS') || '[]'); + const specialSelectors: string[] = JSON.parse(ConfigService.get('ETH_CALL_CONSENSUS_SELECTORS')); const shouldForceToConsensus = selector !== '' && specialSelectors.includes(selector); // ETH_CALL_DEFAULT_TO_CONSENSUS_NODE = false enables the use of Mirror node diff --git a/packages/relay/src/lib/net.ts b/packages/relay/src/lib/net.ts index 12394f9d2e..ccdc3baa23 100644 --- a/packages/relay/src/lib/net.ts +++ b/packages/relay/src/lib/net.ts @@ -19,7 +19,6 @@ */ import { Net } from '../index'; -import constants from './constants'; import { Client } from '@hashgraph/sdk'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; @@ -30,10 +29,7 @@ export class NetImpl implements Net { constructor(client: Client) { this.client = client; - // @ts-ignore - const hederaNetwork: string = (ConfigService.get('HEDERA_NETWORK') || '{}').toLowerCase(); - this.chainId = ConfigService.get('CHAIN_ID') || constants.CHAIN_IDS[hederaNetwork] || '298'; - if (this.chainId.startsWith('0x')) this.chainId = parseInt(this.chainId, 16).toString(); + this.chainId = parseInt(ConfigService.get('CHAIN_ID'), 16).toString(); } /** diff --git a/packages/relay/src/lib/poller.ts b/packages/relay/src/lib/poller.ts index 01536bf1c6..22fc8da88e 100644 --- a/packages/relay/src/lib/poller.ts +++ b/packages/relay/src/lib/poller.ts @@ -50,9 +50,8 @@ export class Poller { this.eth = eth; this.logger = logger; this.polls = []; - this.pollingInterval = Number(ConfigService.get('WS_POLLING_INTERVAL')) || 500; - // @ts-ignore - this.newHeadsEnabled = ConfigService.get('WS_NEW_HEADS_ENABLED') ?? true; + this.pollingInterval = ConfigService.get('WS_POLLING_INTERVAL'); + this.newHeadsEnabled = ConfigService.get('WS_NEW_HEADS_ENABLED'); const activePollsGaugeName = 'rpc_websocket_active_polls'; register.removeSingleMetric(activePollsGaugeName); diff --git a/packages/relay/src/lib/precheck.ts b/packages/relay/src/lib/precheck.ts index 27a0e8ac54..be0f8bcf75 100644 --- a/packages/relay/src/lib/precheck.ts +++ b/packages/relay/src/lib/precheck.ts @@ -18,6 +18,7 @@ * */ +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { ethers, Transaction } from 'ethers'; import { Logger } from 'pino'; @@ -357,7 +358,7 @@ export class Precheck { checkSize(transaction: string): void { const transactionToBytes: Uint8Array = this.hexToBytes(transaction); const transactionSize: number = transactionToBytes.length; - const transactionSizeLimit: number = constants.SEND_RAW_TRANSACTION_SIZE_LIMIT; + const transactionSizeLimit: number = ConfigService.get('SEND_RAW_TRANSACTION_SIZE_LIMIT'); if (transactionSize > transactionSizeLimit) { throw predefined.TRANSACTION_SIZE_TOO_BIG(String(transactionSize), String(transactionSizeLimit)); diff --git a/packages/relay/src/lib/relay.ts b/packages/relay/src/lib/relay.ts index a90feb34f4..eac5110629 100644 --- a/packages/relay/src/lib/relay.ts +++ b/packages/relay/src/lib/relay.ts @@ -130,10 +130,7 @@ export class RelayImpl implements Relay { ) { logger.info('Configurations successfully loaded'); - // @ts-ignore - const hederaNetwork: string = (ConfigService.get('HEDERA_NETWORK') || '{}').toLowerCase(); - const configuredChainId = ConfigService.get('CHAIN_ID') || constants.CHAIN_IDS[hederaNetwork] || '298'; - const chainId = prepend0x(Number(configuredChainId).toString(16)); + const chainId = ConfigService.get('CHAIN_ID'); const duration = constants.HBAR_RATE_LIMIT_DURATION; this.eventEmitter = new EventEmitter(); @@ -169,13 +166,12 @@ export class RelayImpl implements Relay { this.netImpl = new NetImpl(this.clientMain); this.mirrorNodeClient = new MirrorNodeClient( - // @ts-ignore - ConfigService.get('MIRROR_NODE_URL') || '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), register, this.cacheService, undefined, - ConfigService.get('MIRROR_NODE_URL_WEB3') || ConfigService.get('MIRROR_NODE_URL') || '', + ConfigService.get('MIRROR_NODE_URL_WEB3') || ConfigService.get('MIRROR_NODE_URL'), ); this.metricService = new MetricService( diff --git a/packages/relay/src/lib/services/cacheService/cacheService.ts b/packages/relay/src/lib/services/cacheService/cacheService.ts index ee735aacb1..1db3b10b27 100644 --- a/packages/relay/src/lib/services/cacheService/cacheService.ts +++ b/packages/relay/src/lib/services/cacheService/cacheService.ts @@ -97,9 +97,7 @@ export class CacheService { this.internalCache = new LocalLRUCache(logger.child({ name: 'localLRUCache' }), register, reservedKeys); this.sharedCache = this.internalCache; - // @ts-ignore this.isSharedCacheEnabled = !ConfigService.get('TEST') && this.isRedisEnabled(); - // @ts-ignore this.shouldMultiSet = ConfigService.get('MULTI_SET'); if (this.isSharedCacheEnabled) { @@ -195,7 +193,6 @@ export class CacheService { * @returns {boolean} Returns true if Redis caching is enabled, otherwise false. */ public isRedisEnabled(): boolean { - // @ts-ignore return ConfigService.get('REDIS_ENABLED') && !!ConfigService.get('REDIS_URL'); } diff --git a/packages/relay/src/lib/services/ethService/ethCommonService/index.ts b/packages/relay/src/lib/services/ethService/ethCommonService/index.ts index ab4a822654..80d4c0ff90 100644 --- a/packages/relay/src/lib/services/ethService/ethCommonService/index.ts +++ b/packages/relay/src/lib/services/ethService/ethCommonService/index.ts @@ -82,7 +82,7 @@ export class CommonService implements ICommonService { private readonly maxTimestampParamRange = 604800; // 7 days private getLogsBlockRangeLimit() { - return parseNumericEnvVar('ETH_GET_LOGS_BLOCK_RANGE_LIMIT', 'DEFAULT_ETH_GET_LOGS_BLOCK_RANGE_LIMIT'); + return ConfigService.get('ETH_GET_LOGS_BLOCK_RANGE_LIMIT'); } constructor(mirrorNodeClient: MirrorNodeClient, logger: Logger, cacheService: CacheService) { diff --git a/packages/relay/src/lib/services/hapiService/hapiService.ts b/packages/relay/src/lib/services/hapiService/hapiService.ts index 88fe3327c2..337615e531 100644 --- a/packages/relay/src/lib/services/hapiService/hapiService.ts +++ b/packages/relay/src/lib/services/hapiService/hapiService.ts @@ -194,19 +194,16 @@ export default class HAPIService { this.logger = logger; this.hbarLimitService = hbarLimitService; this.eventEmitter = eventEmitter; - this.hederaNetwork = ((ConfigService.get('HEDERA_NETWORK') as string) || '{}').toLowerCase(); + this.hederaNetwork = ConfigService.get('HEDERA_NETWORK').toLowerCase(); this.clientMain = this.initClient(logger, this.hederaNetwork); this.cacheService = cacheService; this.client = this.initSDKClient(logger); const currentDateNow = Date.now(); - // @ts-ignore - this.initialTransactionCount = parseInt(ConfigService.get('HAPI_CLIENT_TRANSACTION_RESET')!) || 0; - // @ts-ignore - this.initialResetDuration = parseInt(ConfigService.get('HAPI_CLIENT_DURATION_RESET')!) || 0; - // @ts-ignore - this.initialErrorCodes = JSON.parse(ConfigService.get('HAPI_CLIENT_ERROR_RESET') || '[21, 50]'); + this.initialTransactionCount = ConfigService.get('HAPI_CLIENT_TRANSACTION_RESET'); + this.initialResetDuration = ConfigService.get('HAPI_CLIENT_DURATION_RESET'); + this.initialErrorCodes = JSON.parse(ConfigService.get('HAPI_CLIENT_ERROR_RESET')); this.transactionCount = this.initialTransactionCount; this.resetDuration = currentDateNow + this.initialResetDuration; @@ -326,11 +323,9 @@ export default class HAPIService { client.setOperator(operator.accountId, operator.privateKey); } - // @ts-ignore - client.setTransportSecurity(ConfigService.get('CLIENT_TRANSPORT_SECURITY') ?? false); + client.setTransportSecurity(ConfigService.get('CLIENT_TRANSPORT_SECURITY')); - // @ts-ignore - const SDK_REQUEST_TIMEOUT = parseInt(ConfigService.get('SDK_REQUEST_TIMEOUT') || '10000'); + const SDK_REQUEST_TIMEOUT = ConfigService.get('SDK_REQUEST_TIMEOUT'); client.setRequestTimeout(SDK_REQUEST_TIMEOUT); logger.info( diff --git a/packages/relay/src/lib/subscriptionController.ts b/packages/relay/src/lib/subscriptionController.ts index 7e81a6d70e..d53199e433 100644 --- a/packages/relay/src/lib/subscriptionController.ts +++ b/packages/relay/src/lib/subscriptionController.ts @@ -18,15 +18,16 @@ * */ -import { Logger } from 'pino'; -import LRU from 'lru-cache'; -import crypto from 'crypto'; -import constants from './constants'; -import { Poller } from './poller'; -import { generateRandomHex } from '../formatters'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import crypto from 'crypto'; +import LRU from 'lru-cache'; +import { Logger } from 'pino'; import { Counter, Histogram, Registry } from 'prom-client'; + +import { generateRandomHex } from '../formatters'; import { Subs } from '../index'; +import constants from './constants'; +import { Poller } from './poller'; export interface Subscriber { connection: any; @@ -34,7 +35,7 @@ export interface Subscriber { endTimer: () => void; } -const CACHE_TTL = Number(ConfigService.get('WS_CACHE_TTL')) || 20000; +const CACHE_TTL = ConfigService.get('WS_CACHE_TTL'); export class SubscriptionController implements Subs { private poller: Poller; @@ -49,7 +50,7 @@ export class SubscriptionController implements Subs { this.logger = logger; this.subscriptions = {}; - this.cache = new LRU({ max: constants.CACHE_MAX, ttl: CACHE_TTL }); + this.cache = new LRU({ max: ConfigService.get('CACHE_MAX'), ttl: CACHE_TTL }); const activeSubscriptionHistogramName = 'rpc_websocket_subscription_times'; register.removeSingleMetric(activeSubscriptionHistogramName); @@ -101,7 +102,7 @@ export class SubscriptionController implements Subs { this.subscriptions[tag] = []; } - if (ConfigService.get('WS_SAME_SUB_FOR_SAME_EVENT') ?? true) { + if (ConfigService.get('WS_SAME_SUB_FOR_SAME_EVENT')) { // Check if the connection is already subscribed to this event const existingSub = this.subscriptions[tag].find((sub) => sub.connection.id === connection.id); if (existingSub) { diff --git a/packages/relay/src/lib/web3.ts b/packages/relay/src/lib/web3.ts index 21d7d2489a..77a7822dd5 100644 --- a/packages/relay/src/lib/web3.ts +++ b/packages/relay/src/lib/web3.ts @@ -30,6 +30,6 @@ export class Web3Impl implements Web3 { } clientVersion(): string { - return 'relay/' + (ConfigService.get('npm_package_version') ?? ''); + return 'relay/' + ConfigService.get('npm_package_version'); } } diff --git a/packages/relay/src/utils.ts b/packages/relay/src/utils.ts index f7b5c13bc9..06840c52fc 100644 --- a/packages/relay/src/utils.ts +++ b/packages/relay/src/utils.ts @@ -40,8 +40,7 @@ export class Utils { // buffered gas price = 126 + 12.6 = 138.6 <--- invalid tinybars gasPrice += Math.round( - (gasPrice / constants.TINYBAR_TO_WEIBAR_COEF) * - (Number(ConfigService.get('GAS_PRICE_PERCENTAGE_BUFFER') || 0) / 100), + (gasPrice / constants.TINYBAR_TO_WEIBAR_COEF) * (ConfigService.get('GAS_PRICE_PERCENTAGE_BUFFER') / 100), ) * constants.TINYBAR_TO_WEIBAR_COEF; return gasPrice; @@ -153,8 +152,8 @@ export class Utils { operatorId = ConfigService.get('OPERATOR_ID_ETH_SENDRAWTRANSACTION') as string; operatorKey = ConfigService.get('OPERATOR_KEY_ETH_SENDRAWTRANSACTION') as string; } else { - operatorId = ConfigService.get('OPERATOR_ID_MAIN') as string; - operatorKey = ConfigService.get('OPERATOR_KEY_MAIN') as string; + operatorId = ConfigService.get('OPERATOR_ID_MAIN'); + operatorKey = ConfigService.get('OPERATOR_KEY_MAIN'); } if (!operatorId || !operatorKey) { diff --git a/packages/relay/tests/helpers.ts b/packages/relay/tests/helpers.ts index e0531f8155..bc8d1ebebd 100644 --- a/packages/relay/tests/helpers.ts +++ b/packages/relay/tests/helpers.ts @@ -29,6 +29,7 @@ import { RedisInMemoryServer } from './redisInMemoryServer'; import { Logger } from 'pino'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { ConfigServiceTestHelper } from '../../config-service/tests/configServiceTestHelper'; +import { ConfigKey } from '@hashgraph/json-rpc-config-service/dist/services/globalConfig'; // Randomly generated key const defaultPrivateKey = '8841e004c6f47af679c91d9282adc62aeb9fabd19cdff6a9da5a358d0613c30a'; @@ -940,7 +941,7 @@ export const overrideEnvsInMochaDescribe = (envs: NodeJS.Dict) => { before(() => { for (const key in envs) { - envsToReset[key] = ConfigService.get(key); + envsToReset[key] = ConfigService.get(key as ConfigKey); overrideEnv(key, envs[key]); } }); diff --git a/packages/relay/tests/lib/clients/localLRUCache.spec.ts b/packages/relay/tests/lib/clients/localLRUCache.spec.ts index d879243416..6fb65295b1 100644 --- a/packages/relay/tests/lib/clients/localLRUCache.spec.ts +++ b/packages/relay/tests/lib/clients/localLRUCache.spec.ts @@ -189,7 +189,7 @@ describe('LocalLRUCache Test Suite', async function () { }); // set default cache ttl to 100ms to test the default ttl will be overridden by the ttl passed in set method - withOverriddenEnvsInMochaTest({ CACHE_TTL: '100' }, async () => { + withOverriddenEnvsInMochaTest({ CACHE_TTL: 100 }, async () => { it('it should set without TTL if -1 is passed for TTL', async () => { const customLocalLRUCache = new LocalLRUCache(logger.child({ name: `cache` }), registry); const lruCacheSpy = sinon.spy(customLocalLRUCache['cache']); diff --git a/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts b/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts index 9383d40ed9..204e1475c8 100644 --- a/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts +++ b/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts @@ -77,8 +77,8 @@ describe('HbarSpendingPlanConfigService', function () { overrideEnvsInMochaDescribe({ HBAR_SPENDING_PLANS_CONFIG: hbarSpendingPlansConfigEnv, - CACHE_TTL: '100', - CACHE_MAX: spendingPlansConfig.length.toString(), + CACHE_TTL: 100, + CACHE_MAX: spendingPlansConfig.length, }); before(async function () { @@ -385,7 +385,7 @@ describe('HbarSpendingPlanConfigService', function () { it('should not delete pre-configured spending plans after default cache TTL expires', async function () { await hbarSpendingPlanConfigService.populatePreconfiguredSpendingPlans(); - await new Promise((resolve) => setTimeout(resolve, Number(ConfigService.get('CACHE_TTL')))); + await new Promise((resolve) => setTimeout(resolve, ConfigService.get('CACHE_TTL'))); await verifySpendingPlans(spendingPlansConfig); }); diff --git a/packages/relay/tests/lib/eth/eth-config.ts b/packages/relay/tests/lib/eth/eth-config.ts index 98077f00fd..69afca2bfc 100644 --- a/packages/relay/tests/lib/eth/eth-config.ts +++ b/packages/relay/tests/lib/eth/eth-config.ts @@ -19,6 +19,9 @@ */ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; + +import { nanOrNumberTo0x, numberTo0x } from '../../../dist/formatters'; +import constants from '../../../src/lib/constants'; import { defaultDetailedContractResultByHash, defaultEvmAddress, @@ -29,8 +32,6 @@ import { mockData, toHex, } from '../../helpers'; -import { numberTo0x, nanOrNumberTo0x } from '../../../dist/formatters'; -import constants from '../../../src/lib/constants'; export const BLOCK_TRANSACTION_COUNT = 77; export const GAS_USED_1 = 200000; @@ -119,7 +120,7 @@ export const CONTRACT_RESULT_MOCK = { }; export const CONTRACT_CALL_DATA = '0xef641f44'; -export const ETH_FEE_HISTORY_VALUE = ConfigService.get('ETH_FEE_HISTORY_FIXED') ?? true; +export const ETH_FEE_HISTORY_VALUE = ConfigService.get('ETH_FEE_HISTORY_FIXED'); export const BLOCK_HASH_PREV_TRIMMED = '0xf7d6481f659c866c35391ee230c374f163642ebf13a5e604e04a95a9ca48a298'; export const BLOCK_NUMBER_HEX = `0x${BLOCK_NUMBER.toString(16)}`; export const MAX_GAS_LIMIT = 250000; diff --git a/packages/relay/tests/lib/eth/eth-helpers.ts b/packages/relay/tests/lib/eth/eth-helpers.ts index 00bc072b34..b690be7a96 100644 --- a/packages/relay/tests/lib/eth/eth-helpers.ts +++ b/packages/relay/tests/lib/eth/eth-helpers.ts @@ -55,7 +55,7 @@ export function generateEthTestEnv(fixedFeeHistory = false) { const cacheService = new CacheService(logger.child({ name: `cache` }), registry); // @ts-ignore const mirrorNodeInstance = new MirrorNodeClient( - ConfigService.get('MIRROR_NODE_URL') || '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, cacheService, diff --git a/packages/relay/tests/lib/eth/eth_common.spec.ts b/packages/relay/tests/lib/eth/eth_common.spec.ts index ab05ce2036..8f088899ab 100644 --- a/packages/relay/tests/lib/eth/eth_common.spec.ts +++ b/packages/relay/tests/lib/eth/eth_common.spec.ts @@ -42,8 +42,7 @@ describe('@ethCommon', async function () { describe('@ethCommon', async function () { it('should execute "eth_chainId"', async function () { const chainId = Relay.eth().chainId(requestDetails); - - expect(chainId).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(chainId).to.be.equal(ConfigService.get('CHAIN_ID')); }); it('should execute "eth_accounts"', async function () { diff --git a/packages/relay/tests/lib/eth/eth_feeHistory.spec.ts b/packages/relay/tests/lib/eth/eth_feeHistory.spec.ts index 513e89a34a..948fffde96 100644 --- a/packages/relay/tests/lib/eth/eth_feeHistory.spec.ts +++ b/packages/relay/tests/lib/eth/eth_feeHistory.spec.ts @@ -145,6 +145,7 @@ describe('@ethFeeHistory using MirrorNode', async function () { }); it('eth_feeHistory with max results', async function () { + overrideEnvsInMochaDescribe({ ETH_FEE_HISTORY_FIXED: false }); const maxResultsCap = Number(constants.DEFAULT_FEE_HISTORY_MAX_RESULTS); restMock.onGet(BLOCKS_LIMIT_ORDER_URL).reply(200, JSON.stringify({ blocks: [{ ...DEFAULT_BLOCK, number: 10 }] })); diff --git a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts index 9ec70f5173..b1da045382 100644 --- a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts +++ b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts @@ -115,7 +115,7 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () }, }; const transaction = { - chainId: Number(ConfigService.get('CHAIN_ID') || 0x12a), + chainId: Number(ConfigService.get('CHAIN_ID')), to: ACCOUNT_ADDRESS_1, from: accountAddress, value, @@ -135,7 +135,7 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () }, receiver_sig_required: false, }; - const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING') as boolean; + const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING'); beforeEach(() => { clock = useFakeTimers(); diff --git a/packages/relay/tests/lib/ethGetBlockBy.spec.ts b/packages/relay/tests/lib/ethGetBlockBy.spec.ts index 105af5e97c..00985df95d 100644 --- a/packages/relay/tests/lib/ethGetBlockBy.spec.ts +++ b/packages/relay/tests/lib/ethGetBlockBy.spec.ts @@ -128,7 +128,7 @@ describe('eth_getBlockBy', async function () { // @ts-ignore mirrorNodeInstance = new MirrorNodeClient( - ConfigService.get('MIRROR_NODE_URL') ?? '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, cacheService, diff --git a/packages/relay/tests/lib/hapiService.spec.ts b/packages/relay/tests/lib/hapiService.spec.ts index b9581784f7..7acafb6b08 100644 --- a/packages/relay/tests/lib/hapiService.spec.ts +++ b/packages/relay/tests/lib/hapiService.spec.ts @@ -123,7 +123,7 @@ describe('HAPI Service', async function () { withOverriddenEnvsInMochaTest({ HAPI_CLIENT_ERROR_RESET: '[50]' }, () => { it('should be able to reinitialise SDK instance upon error status code encounter', async function () { - const hapiClientErrorReset: Array = JSON.parse(ConfigService.get('HAPI_CLIENT_ERROR_RESET') as string); + const hapiClientErrorReset: Array = JSON.parse(ConfigService.get('HAPI_CLIENT_ERROR_RESET')); hapiService = new HAPIService(logger, registry, cacheService, eventEmitter, hbarLimitService); expect(hapiService.getErrorCodes()[0]).to.eq(hapiClientErrorReset[0]); diff --git a/packages/relay/tests/lib/mirrorNodeClient.spec.ts b/packages/relay/tests/lib/mirrorNodeClient.spec.ts index ff239201e9..a05591c527 100644 --- a/packages/relay/tests/lib/mirrorNodeClient.spec.ts +++ b/packages/relay/tests/lib/mirrorNodeClient.spec.ts @@ -22,10 +22,6 @@ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services' import axios, { AxiosInstance } from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { BigNumber } from 'bignumber.js'; -import { expect } from 'chai'; -import { ethers } from 'ethers'; -import pino from 'pino'; -import { Registry } from 'prom-client'; import { MirrorNodeClientError, predefined } from '../../src'; import { MirrorNodeClient } from '../../src/lib/clients'; @@ -34,6 +30,10 @@ import { SDKClientError } from '../../src/lib/errors/SDKClientError'; import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import { MirrorNodeTransactionRecord, RequestDetails } from '../../src/lib/types'; import { mockData, random20BytesAddress, withOverriddenEnvsInMochaTest } from '../helpers'; +import { expect } from 'chai'; +import { Registry } from 'prom-client'; +import pino from 'pino'; +import { ethers } from 'ethers'; describe('MirrorNodeClient', async function () { this.timeout(20000); @@ -57,8 +57,7 @@ describe('MirrorNodeClient', async function () { }); cacheService = new CacheService(logger.child({ name: `cache` }), registry); mirrorNodeInstance = new MirrorNodeClient( - // @ts-ignore - ConfigService.get('MIRROR_NODE_URL') || '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, cacheService, @@ -134,8 +133,7 @@ describe('MirrorNodeClient', async function () { }); it('`restUrl` is exposed and correct', async () => { - // @ts-ignore - const domain = (ConfigService.get('MIRROR_NODE_URL') || '').replace(/^https?:\/\//, ''); + const domain = ConfigService.get('MIRROR_NODE_URL').replace(/^https?:\/\//, ''); const prodMirrorNodeInstance = new MirrorNodeClient( domain, logger.child({ name: `mirror-node` }), @@ -162,7 +160,7 @@ describe('MirrorNodeClient', async function () { withOverriddenEnvsInMochaTest({ MIRROR_NODE_URL_HEADER_X_API_KEY: 'abc123iAManAPIkey' }, () => { it('Can provide custom x-api-key header', async () => { const mirrorNodeInstanceOverridden = new MirrorNodeClient( - ConfigService.get('MIRROR_NODE_URL') || '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, cacheService, diff --git a/packages/relay/tests/lib/net.spec.ts b/packages/relay/tests/lib/net.spec.ts index 9299aed62e..eb388754a2 100644 --- a/packages/relay/tests/lib/net.spec.ts +++ b/packages/relay/tests/lib/net.spec.ts @@ -23,7 +23,6 @@ import { expect } from 'chai'; import pino from 'pino'; import { Registry } from 'prom-client'; -import constants from '../../src/lib/constants'; import { RelayImpl } from '../../src/lib/relay'; import { withOverriddenEnvsInMochaTest } from '../helpers'; @@ -31,19 +30,15 @@ const logger = pino({ level: 'silent' }); let Relay; describe('Net', async function () { - this.beforeEach(() => { - Relay = new RelayImpl(logger, new Registry()); - }); - it('should execute "net_listening"', function () { + Relay = new RelayImpl(logger, new Registry()); const result = Relay.net().listening(); expect(result).to.eq(false); }); it('should execute "net_version"', function () { - const hederaNetwork: string = (ConfigService.get('HEDERA_NETWORK') || '{}').toLowerCase(); - let expectedNetVersion = ConfigService.get('CHAIN_ID') || constants.CHAIN_IDS[hederaNetwork] || '298'; - if (expectedNetVersion.startsWith('0x')) expectedNetVersion = parseInt(expectedNetVersion, 16).toString(); + Relay = new RelayImpl(logger, new Registry()); + let expectedNetVersion = parseInt(ConfigService.get('CHAIN_ID'), 16).toString(); const actualNetVersion = Relay.net().version(); expect(actualNetVersion).to.eq(expectedNetVersion); @@ -65,19 +60,11 @@ describe('Net', async function () { }); }); - withOverriddenEnvsInMochaTest({ HEDERA_NETWORK: undefined, CHAIN_ID: undefined }, () => { - it('should default chainId to 298 when no environment variables are set', () => { - Relay = new RelayImpl(logger, new Registry()); - const actualNetVersion = Relay.net().version(); - expect(actualNetVersion).to.equal('298'); - }); - }); - - withOverriddenEnvsInMochaTest({ HEDERA_NETWORK: '', CHAIN_ID: undefined }, () => { - it('should handle empty HEDERA_NETWORK and set chainId to default', () => { - Relay = new RelayImpl(logger, new Registry()); - const actualNetVersion = Relay.net().version(); - expect(actualNetVersion).to.equal('298'); + withOverriddenEnvsInMochaTest({ HEDERA_NETWORK: undefined }, () => { + it('should throw error if required configuration is set to undefined', () => { + expect(() => new RelayImpl(logger, new Registry())).to.throw( + 'Configuration error: HEDERA_NETWORK is a mandatory configuration for relay operation.', + ); }); }); diff --git a/packages/relay/tests/lib/openrpc.spec.ts b/packages/relay/tests/lib/openrpc.spec.ts index 2cf7333011..21345275b9 100644 --- a/packages/relay/tests/lib/openrpc.spec.ts +++ b/packages/relay/tests/lib/openrpc.spec.ts @@ -122,7 +122,7 @@ describe('Open RPC Specification', function () { const cacheService = new CacheService(logger.child({ name: `cache` }), registry); // @ts-ignore mirrorNodeInstance = new MirrorNodeClient( - ConfigService.get('MIRROR_NODE_URL') || '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, cacheService, diff --git a/packages/relay/tests/lib/poller.spec.ts b/packages/relay/tests/lib/poller.spec.ts index 245e302e84..75333a38f8 100644 --- a/packages/relay/tests/lib/poller.spec.ts +++ b/packages/relay/tests/lib/poller.spec.ts @@ -19,12 +19,13 @@ */ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import { EthImpl } from '../../src/lib/eth'; import { expect } from 'chai'; import pino from 'pino'; -import { Poller } from '../../src/lib/poller'; -import sinon from 'sinon'; import { Registry } from 'prom-client'; +import sinon from 'sinon'; + +import { EthImpl } from '../../src/lib/eth'; +import { Poller } from '../../src/lib/poller'; const logger = pino({ level: 'trace' }); @@ -187,7 +188,9 @@ describe('Polling', async function () { ), ).to.equal(true); expect( - loggerSpy.calledWith(`Poller: Starting polling with interval=${ConfigService.get('WS_POLLING_INTERVAL')}`), + loggerSpy.calledWith( + `Poller: Starting polling with interval=${ConfigService.get('WS_POLLING_INTERVAL')}`, + ), ).to.equal(true); }); diff --git a/packages/relay/tests/lib/sdkClient.spec.ts b/packages/relay/tests/lib/sdkClient.spec.ts index 1da06e1563..8e70f7cb07 100644 --- a/packages/relay/tests/lib/sdkClient.spec.ts +++ b/packages/relay/tests/lib/sdkClient.spec.ts @@ -148,7 +148,7 @@ describe('SdkClient', async function () { // mirror node client mirrorNodeClient = new MirrorNodeClient( - ConfigService.get('MIRROR_NODE_URL') || '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, new CacheService(logger.child({ name: `cache` }), registry), @@ -335,8 +335,8 @@ describe('SdkClient', async function () { }); describe('HBAR Limiter', async () => { - const FILE_APPEND_CHUNK_SIZE = Number(ConfigService.get('FILE_APPEND_CHUNK_SIZE')) || 5120; - const MAX_CHUNKS = Number(ConfigService.get('FILE_APPEND_MAX_CHUNKS')) || 20; + const FILE_APPEND_CHUNK_SIZE = ConfigService.get('FILE_APPEND_CHUNK_SIZE'); + const MAX_CHUNKS = ConfigService.get('FILE_APPEND_MAX_CHUNKS'); const transactionBuffer = new Uint8Array([ 2, 249, 250, 182, 130, 1, 42, 7, 1, 133, 209, 56, 92, 123, 240, 131, 228, 225, 192, 148, 61, 176, 51, 137, 34, 205, 229, 74, 102, 224, 197, 133, 1, 18, 73, 145, 93, 50, 210, 37, 134, 9, 24, 78, 114, 160, 0, 185, 250, 68, 130, @@ -2743,7 +2743,7 @@ describe('SdkClient', async function () { }); it('Should execute getTransferAmountSumForAccount() to calculate transactionFee by only transfers that are paid by the specify accountId', () => { - const accountId = ConfigService.get('OPERATOR_ID_MAIN') || ''; + const accountId = ConfigService.get('OPERATOR_ID_MAIN'); const mockedTxRecord = getMockedTransactionRecord(EthereumTransaction.name, true); const transactionFee = sdkClient.getTransferAmountSumForAccount(mockedTxRecord, accountId); diff --git a/packages/relay/tests/lib/services/eth/filter.spec.ts b/packages/relay/tests/lib/services/eth/filter.spec.ts index ca97a84a8f..daf66e4fe0 100644 --- a/packages/relay/tests/lib/services/eth/filter.spec.ts +++ b/packages/relay/tests/lib/services/eth/filter.spec.ts @@ -111,7 +111,7 @@ describe('Filter API Test Suite', async function () { }); describe('all methods require a filter flag', async function () { - withOverriddenEnvsInMochaTest({ FILTER_API_ENABLED: undefined }, () => { + withOverriddenEnvsInMochaTest({ FILTER_API_ENABLED: false }, () => { it(`should throw UNSUPPORTED_METHOD for newFilter`, async function () { await RelayAssertions.assertRejection( predefined.UNSUPPORTED_METHOD, diff --git a/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts b/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts index 5a97deeecb..4299c86b21 100644 --- a/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts +++ b/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts @@ -24,7 +24,6 @@ import { AccountId, Hbar } from '@hashgraph/sdk'; import chai, { expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; import { randomBytes, uuidV4 } from 'ethers'; -import { Long } from 'long'; import pino, { Logger } from 'pino'; import { Counter, Gauge, Registry } from 'prom-client'; import sinon from 'sinon'; @@ -190,14 +189,12 @@ describe('HBAR Rate Limit Service', function () { describe('shouldLimit', function () { const operatorEnvs = [ - { OPERATOR_ID_MAIN: ConfigService.get('OPERATOR_ID_MAIN') as string }, - { OPERATOR_ID_MAIN: null }, + { OPERATOR_ID_MAIN: ConfigService.get('OPERATOR_ID_MAIN') }, + { OPERATOR_ID_MAIN: zeroAddress() }, ]; operatorEnvs.forEach((operatorEnv) => { - const operatorAddress = operatorEnv.OPERATOR_ID_MAIN - ? prepend0x(AccountId.fromString(operatorEnv.OPERATOR_ID_MAIN).toSolidityAddress()) - : zeroAddress(); + const operatorAddress = prepend0x(AccountId.fromString(operatorEnv.OPERATOR_ID_MAIN).toSolidityAddress()); withOverriddenEnvsInMochaTest(operatorEnv, () => { describe('based on evmAddress', async function () { @@ -881,8 +878,8 @@ describe('HBAR Rate Limit Service', function () { }; const operatorEnvs = [ - { OPERATOR_ID_MAIN: ConfigService.get('OPERATOR_ID_MAIN') as string }, - { OPERATOR_ID_MAIN: null }, + { OPERATOR_ID_MAIN: ConfigService.get('OPERATOR_ID_MAIN') }, + { OPERATOR_ID_MAIN: zeroAddress() }, ]; operatorEnvs.forEach((operatorEnv) => { @@ -957,8 +954,8 @@ describe('HBAR Rate Limit Service', function () { }; const operatorEnvs = [ - { OPERATOR_ID_MAIN: ConfigService.get('OPERATOR_ID_MAIN') as string }, - { OPERATOR_ID_MAIN: null }, + { OPERATOR_ID_MAIN: ConfigService.get('OPERATOR_ID_MAIN') }, + { OPERATOR_ID_MAIN: zeroAddress() }, ]; operatorEnvs.forEach((operatorEnv) => { diff --git a/packages/relay/tests/lib/services/metricService/metricService.spec.ts b/packages/relay/tests/lib/services/metricService/metricService.spec.ts index f2b2b6d6ad..017f77141b 100644 --- a/packages/relay/tests/lib/services/metricService/metricService.spec.ts +++ b/packages/relay/tests/lib/services/metricService/metricService.spec.ts @@ -144,15 +144,15 @@ describe('Metric Service', function () { before(() => { // consensus node client - const hederaNetwork = ConfigService.get('HEDERA_NETWORK')! as string; + const hederaNetwork = ConfigService.get('HEDERA_NETWORK')!; if (hederaNetwork in constants.CHAIN_IDS) { client = Client.forName(hederaNetwork); } else { client = Client.forNetwork(JSON.parse(hederaNetwork)); } client = client.setOperator( - AccountId.fromString(ConfigService.get('OPERATOR_ID_MAIN')! as string), - Utils.createPrivateKeyBasedOnFormat(ConfigService.get('OPERATOR_KEY_MAIN')! as string), + AccountId.fromString(ConfigService.get('OPERATOR_ID_MAIN')!), + Utils.createPrivateKeyBasedOnFormat(ConfigService.get('OPERATOR_KEY_MAIN')!), ); // mirror node client @@ -165,7 +165,7 @@ describe('Metric Service', function () { timeout: 20 * 1000, }); mirrorNodeClient = new MirrorNodeClient( - (ConfigService.get('MIRROR_NODE_URL') as string) || '', + ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, new CacheService(logger.child({ name: `cache` }), registry), diff --git a/packages/relay/tests/lib/utils.spec.ts b/packages/relay/tests/lib/utils.spec.ts index e1e40c495d..83831ee2d4 100644 --- a/packages/relay/tests/lib/utils.spec.ts +++ b/packages/relay/tests/lib/utils.spec.ts @@ -61,7 +61,7 @@ describe('Utils', () => { describe('estimateFileTransactionsFee', () => { const callDataSize = 6000; const mockedExchangeRateInCents: number = 12; - const fileChunkSize = Number(ConfigService.get('FILE_APPEND_CHUNK_SIZE')) || 5120; + const fileChunkSize = ConfigService.get('FILE_APPEND_CHUNK_SIZE'); it('Should execute estimateFileTransactionFee() to estimate total fee of file transactions', async () => { const result = Utils.estimateFileTransactionsFee(callDataSize, fileChunkSize, mockedExchangeRateInCents); const expectedResult = estimateFileTransactionsFee(callDataSize, fileChunkSize, mockedExchangeRateInCents); @@ -83,7 +83,6 @@ describe('Utils', () => { ).to.be.false; }); - // @ts-ignore JSON.parse(ConfigService.get('HEDERA_SPECIFIC_REVERT_STATUSES')).forEach((status) => { it(`should exclude transaction with result ${status}`, () => { expect(Utils.isRevertedDueToHederaSpecificValidation({ result: status, error_message: null })).to.be.true; @@ -181,15 +180,10 @@ describe('Utils', () => { OPERATOR_KEY_MAIN: null, }, () => { - it('should return null and log a warning if operatorKey is missing', () => { - const warnSpy = sinon.spy(logger, 'warn'); - - const operator = Utils.getOperator(logger); - - expect(operator).to.be.null; - expect(warnSpy.calledOnce).to.be.true; - expect(warnSpy.firstCall.args[0]).to.equal('Invalid operatorId or operatorKey for main client.'); - warnSpy.restore(); + it('should throw error if OPERATOR_KEY_MAIN is missing', () => { + expect(() => Utils.getOperator(logger)).to.throw( + 'Configuration error: OPERATOR_KEY_MAIN is a mandatory configuration for relay operation.', + ); }); }, ); @@ -200,15 +194,10 @@ describe('Utils', () => { OPERATOR_KEY_MAIN: privateKeys[0].keyValue, }, () => { - it('should return null and log a warning if operatorId is missing', () => { - const warnSpy = sinon.spy(logger, 'warn'); - - const operator = Utils.getOperator(logger); - - expect(operator).to.be.null; - expect(warnSpy.calledOnce).to.be.true; - expect(warnSpy.firstCall.args[0]).to.equal('Invalid operatorId or operatorKey for main client.'); - warnSpy.restore(); + it('should throw error if OPERATOR_ID_MAIN is missing', () => { + expect(() => Utils.getOperator(logger)).to.throw( + 'Configuration error: OPERATOR_ID_MAIN is a mandatory configuration for relay operation.', + ); }); }, ); diff --git a/packages/relay/tests/lib/web3.spec.ts b/packages/relay/tests/lib/web3.spec.ts index 056e722c90..d9bd3e27b5 100644 --- a/packages/relay/tests/lib/web3.spec.ts +++ b/packages/relay/tests/lib/web3.spec.ts @@ -38,9 +38,10 @@ describe('Web3', function () { }); withOverriddenEnvsInMochaTest({ npm_package_version: undefined }, () => { - it('should return "relay/"', () => { - const version = Relay.web3().clientVersion(); - expect(version).to.equal('relay/'); + it('should throw an error if npm_package_version is undefined', () => { + expect(() => Relay.web3().clientVersion()).to.throw( + 'Configuration error: npm_package_version is a mandatory configuration for relay operation.', + ); }); }); }); diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index ccb4d808d1..ace992b60e 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -23,7 +23,7 @@ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services' import { setServerTimeout } from './koaJsonRpc/lib/utils'; // Import the 'setServerTimeout' function from the correct location async function main() { - const server = app.listen({ port: ConfigService.get('SERVER_PORT') || 7546, host: ConfigService.get('SERVER_HOST') }); + const server = app.listen({ port: ConfigService.get('SERVER_PORT'), host: ConfigService.get('SERVER_HOST') }); // set request timeout to ensure sockets are closed after specified time of inactivity setServerTimeout(server); diff --git a/packages/server/src/koaJsonRpc/lib/methodConfiguration.ts b/packages/server/src/koaJsonRpc/lib/methodConfiguration.ts index ab0f73d519..782d7e5567 100644 --- a/packages/server/src/koaJsonRpc/lib/methodConfiguration.ts +++ b/packages/server/src/koaJsonRpc/lib/methodConfiguration.ts @@ -19,20 +19,10 @@ */ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import CONSTANTS from '@hashgraph/json-rpc-relay/dist/lib/constants'; -const tier1rateLimit = parseInt( - // @ts-ignore - ConfigService.get('TIER_1_RATE_LIMIT') ?? CONSTANTS.DEFAULT_RATE_LIMIT.TIER_1.toString(), -); -const tier2rateLimit = parseInt( - // @ts-ignore - ConfigService.get('TIER_2_RATE_LIMIT') ?? CONSTANTS.DEFAULT_RATE_LIMIT.TIER_2.toString(), -); -const tier3rateLimit = parseInt( - // @ts-ignore - ConfigService.get('TIER_3_RATE_LIMIT') ?? CONSTANTS.DEFAULT_RATE_LIMIT.TIER_3.toString(), -); +const tier1rateLimit = ConfigService.get('TIER_1_RATE_LIMIT'); +const tier2rateLimit = ConfigService.get('TIER_2_RATE_LIMIT'); +const tier3rateLimit = ConfigService.get('TIER_3_RATE_LIMIT'); export interface IMethodRateLimit { total: number; diff --git a/packages/server/src/koaJsonRpc/lib/utils.ts b/packages/server/src/koaJsonRpc/lib/utils.ts index 50a14b4e60..f92bfa700e 100644 --- a/packages/server/src/koaJsonRpc/lib/utils.ts +++ b/packages/server/src/koaJsonRpc/lib/utils.ts @@ -19,7 +19,6 @@ */ import type { Server } from 'http'; -import constants from '@hashgraph/json-rpc-relay/dist/lib/constants'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; export function hasOwnProperty(obj: any, prop: PropertyKey): boolean { @@ -27,32 +26,26 @@ export function hasOwnProperty(obj: any, prop: PropertyKey): boolean { } export function setServerTimeout(server: Server): void { - // @ts-ignore - const requestTimeoutMs = parseInt(ConfigService.get('SERVER_REQUEST_TIMEOUT_MS') ?? '60000'); + const requestTimeoutMs = ConfigService.get('SERVER_REQUEST_TIMEOUT_MS'); server.setTimeout(requestTimeoutMs); } export function getBatchRequestsMaxSize(): number { - // @ts-ignore - return parseInt(ConfigService.get('BATCH_REQUESTS_MAX_SIZE') ?? '100'); + return ConfigService.get('BATCH_REQUESTS_MAX_SIZE'); } export function getLimitDuration(): number { - // @ts-ignore - return parseInt(ConfigService.get('LIMIT_DURATION') ?? constants.DEFAULT_RATE_LIMIT.DURATION.toString()); + return ConfigService.get('LIMIT_DURATION'); } export function getDefaultRateLimit(): number { - // @ts-ignore - return parseInt(ConfigService.get('DEFAULT_RATE_LIMIT') ?? '200'); + return ConfigService.get('DEFAULT_RATE_LIMIT'); } export function getRequestIdIsOptional(): boolean { - // @ts-ignore return ConfigService.get('REQUEST_ID_IS_OPTIONAL'); } export function getBatchRequestsEnabled(): boolean { - // @ts-ignore - return ConfigService.get('BATCH_REQUESTS_ENABLED') ?? false; + return ConfigService.get('BATCH_REQUESTS_ENABLED'); } diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 1e61c86ab8..56b2bf7376 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -18,22 +18,23 @@ * */ -import { JsonRpcError, MirrorNodeClientError, predefined, Relay, RelayImpl } from '@hashgraph/json-rpc-relay/dist'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { JsonRpcError, MirrorNodeClientError, predefined, Relay, RelayImpl } from '@hashgraph/json-rpc-relay/dist'; import { ITracerConfig, RequestDetails } from '@hashgraph/json-rpc-relay/src/lib/types'; -import { collectDefaultMetrics, Histogram, Registry } from 'prom-client'; -import KoaJsonRpc from './koaJsonRpc'; -import { TracerType, TYPES, Validator } from './validator'; -import pino from 'pino'; -import path from 'path'; import fs from 'fs'; +import cors from 'koa-cors'; +import path from 'path'; +import pino from 'pino'; +import { collectDefaultMetrics, Histogram, Registry } from 'prom-client'; import { v4 as uuid } from 'uuid'; + import { formatRequestIdMessage } from './formatters'; -import cors from 'koa-cors'; +import KoaJsonRpc from './koaJsonRpc'; +import { TracerType, TYPES, Validator } from './validator'; const mainLogger = pino({ name: 'hedera-json-rpc-relay', - // @ts-ignore + // Pino requires the default level to be explicitly set; without fallback value ("trace"), an invalid or missing value could trigger the "default level must be included in custom levels" error. level: ConfigService.get('LOG_LEVEL') || 'trace', transport: { target: 'pino-pretty', @@ -48,7 +49,7 @@ const logger = mainLogger.child({ name: 'rpc-server' }); const register = new Registry(); const relay: Relay = new RelayImpl(logger.child({ name: 'relay' }), register); const app = new KoaJsonRpc(logger.child({ name: 'koa-rpc' }), register, { - limit: ConfigService.get('INPUT_SIZE_LIMIT') ? ConfigService.get('INPUT_SIZE_LIMIT') + 'mb' : null, + limit: ConfigService.get('INPUT_SIZE_LIMIT') + 'mb', }); collectDefaultMetrics({ register, prefix: 'rpc_relay_' }); diff --git a/packages/server/tests/acceptance/conformityTests.spec.ts b/packages/server/tests/acceptance/conformityTests.spec.ts index d758ebc949..bd25199585 100644 --- a/packages/server/tests/acceptance/conformityTests.spec.ts +++ b/packages/server/tests/acceptance/conformityTests.spec.ts @@ -1,4 +1,4 @@ -/* +/*- * * Hedera JSON RPC Relay * @@ -68,7 +68,7 @@ addFormats(ajv); let execApisOpenRpcData; let relayOpenRpcData: any; -const chainId = Number(ConfigService.get('CHAIN_ID') || 0x12a); +const chainId = Number(ConfigService.get('CHAIN_ID')); let legacyTransaction = { chainId, diff --git a/packages/server/tests/acceptance/hbarLimiter.spec.ts b/packages/server/tests/acceptance/hbarLimiter.spec.ts index 42cad4c56f..8d335cd070 100644 --- a/packages/server/tests/acceptance/hbarLimiter.spec.ts +++ b/packages/server/tests/acceptance/hbarLimiter.spec.ts @@ -31,7 +31,7 @@ import { ITransfer, RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/ty import { SpendingPlanConfig } from '@hashgraph/json-rpc-relay/src/lib/types/spendingPlanConfig'; import { estimateFileTransactionsFee, overrideEnvsInMochaDescribe } from '@hashgraph/json-rpc-relay/tests/helpers'; import { expect } from 'chai'; -import dotenv, { config } from 'dotenv'; +import { config } from 'dotenv'; import { BaseContract, ethers } from 'ethers'; import findConfig from 'find-config'; import fs from 'fs'; @@ -72,9 +72,9 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { metrics: MetricsClient; relayIsLocal: boolean; } = global; - const mockTTL = ConfigService.get('HBAR_RATE_LIMIT_DURATION') as number; // 1 day - const operatorAccount = ConfigService.get('OPERATOR_ID_MAIN') as string; - const fileAppendChunkSize = Number(ConfigService.get('FILE_APPEND_CHUNK_SIZE')) || 5120; + const mockTTL = ConfigService.get('HBAR_RATE_LIMIT_DURATION'); + const operatorAccount = ConfigService.get('OPERATOR_ID_MAIN'); + const fileAppendChunkSize = Number(ConfigService.get('FILE_APPEND_CHUNK_SIZE')); const requestId = 'hbarLimiterTest'; const requestDetails = new RequestDetails({ requestId: requestId, ipAddress: '0.0.0.0' }); const cacheService = new CacheService(logger.child({ name: 'cache-service' }), new Registry()); @@ -126,7 +126,7 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { return contract; }; - const transactionReecordCostTolerance = Number(ConfigService.get(`TEST_TRANSACTION_RECORD_COST_TOLERANCE`) || 0.02); + const transactionReecordCostTolerance = ConfigService.get('TEST_TRANSACTION_RECORD_COST_TOLERANCE'); const verifyRemainingLimit = (expectedCost: number, remainingHbarsBefore: number, remainingHbarsAfter: number) => { const delta = transactionReecordCostTolerance * expectedCost; @@ -219,7 +219,7 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { const accounts: AliasAccount[] = []; const defaultLondonTransactionData = { value: Utils.add0xPrefix(Utils.toHex(ethers.parseUnits('1', 10))), // 1 tinybar - chainId: Number(ConfigService.get('CHAIN_ID') || 0), + chainId: Number(ConfigService.get('CHAIN_ID')), maxPriorityFeePerGas: Assertions.defaultGasPrice, maxFeePerGas: Assertions.defaultGasPrice, gasLimit: 3_000_000, @@ -738,7 +738,7 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { }; describe('given a valid JSON file with pre-configured spending plans', async () => { - const SPENDING_PLANS_CONFIG_FILE = ConfigService.get('HBAR_SPENDING_PLANS_CONFIG') as string; + const SPENDING_PLANS_CONFIG_FILE = ConfigService.get('HBAR_SPENDING_PLANS_CONFIG'); const configPath = findConfig(SPENDING_PLANS_CONFIG_FILE); if (configPath) { @@ -898,7 +898,7 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { return { ...aliasAccount, hbarSpendingPlan: accountAliasPlan.hbarSpendingPlan }; }); - const totalHbarBudget = ConfigService.get(`HBAR_RATE_LIMIT_TINYBAR`) as number; + const totalHbarBudget = ConfigService.get('HBAR_RATE_LIMIT_TINYBAR'); let totalHbarSpent = totalHbarBudget - Number(await metrics.get(testConstants.METRICS.REMAINING_HBAR_LIMIT)); diff --git a/packages/server/tests/acceptance/index.spec.ts b/packages/server/tests/acceptance/index.spec.ts index db5a4739df..fd47becebd 100644 --- a/packages/server/tests/acceptance/index.spec.ts +++ b/packages/server/tests/acceptance/index.spec.ts @@ -23,8 +23,9 @@ import dotenv from 'dotenv'; import path from 'path'; dotenv.config({ path: path.resolve(__dirname, '../../../../.env') }); -// Constants +// External resources import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +// Constants import constants from '@hashgraph/json-rpc-relay/dist/lib/constants'; import { app as wsApp } from '@hashgraph/json-rpc-ws-server/dist/webSocketServer'; // Hashgraph SDK @@ -56,7 +57,7 @@ describe('RPC Server Acceptance Tests', function () { const testLogger = pino({ name: 'hedera-json-rpc-relay', - level: (ConfigService.get('LOG_LEVEL') as string) || 'trace', + level: ConfigService.get('LOG_LEVEL'), transport: { target: 'pino-pretty', options: { @@ -67,14 +68,14 @@ describe('RPC Server Acceptance Tests', function () { }); const logger = testLogger.child({ name: 'rpc-acceptance-test' }); - const NETWORK = ConfigService.get('HEDERA_NETWORK') as string; - const OPERATOR_KEY = ConfigService.get('OPERATOR_KEY_MAIN') as string; - const OPERATOR_ID = ConfigService.get('OPERATOR_ID_MAIN') as string; - const MIRROR_NODE_URL = ConfigService.get('MIRROR_NODE_URL') as string; + const NETWORK = ConfigService.get('HEDERA_NETWORK'); + const OPERATOR_KEY = ConfigService.get('OPERATOR_KEY_MAIN'); + const OPERATOR_ID = ConfigService.get('OPERATOR_ID_MAIN'); + const MIRROR_NODE_URL = ConfigService.get('MIRROR_NODE_URL'); const LOCAL_RELAY_URL = 'http://localhost:7546'; const RELAY_URL = ConfigService.get('E2E_RELAY_HOST') || LOCAL_RELAY_URL; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || '0x12a'; - const INITIAL_BALANCE = ConfigService.get('INITIAL_BALANCE') || '5000000000'; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); + const INITIAL_BALANCE = ConfigService.get('INITIAL_BALANCE'); global.relayIsLocal = RELAY_URL === LOCAL_RELAY_URL; global.servicesNode = new ServicesClient( @@ -125,7 +126,7 @@ describe('RPC Server Acceptance Tests', function () { RELAY_URL, CHAIN_ID, Utils.generateRequestId(), - Number(ConfigService.get('TEST_INITIAL_ACCOUNT_STARTING_BALANCE') || 2000), + ConfigService.get('TEST_INITIAL_ACCOUNT_STARTING_BALANCE'), ); global.accounts = new Array(initialAccount); diff --git a/packages/server/tests/acceptance/rateLimiter.spec.ts b/packages/server/tests/acceptance/rateLimiter.spec.ts index 679536dc64..a7a10c3644 100644 --- a/packages/server/tests/acceptance/rateLimiter.spec.ts +++ b/packages/server/tests/acceptance/rateLimiter.spec.ts @@ -20,11 +20,11 @@ // Assertions and constants from local resources -import Assertions from '../helpers/assertions'; -import testConstants from '../../tests/helpers/constants'; -import relayConstants from '@hashgraph/json-rpc-relay/dist/lib/constants'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; + +import testConstants from '../../tests/helpers/constants'; import RelayClient from '../clients/relayClient'; +import Assertions from '../helpers/assertions'; describe('@ratelimiter Rate Limiters Acceptance Tests', function () { this.timeout(480 * 1000); // 480 seconds @@ -35,10 +35,8 @@ describe('@ratelimiter Rate Limiters Acceptance Tests', function () { // cached entities let requestId: string; - const TIER_2_RATE_LIMIT = - (ConfigService.get('TIER_2_RATE_LIMIT') as unknown as number) || relayConstants.DEFAULT_RATE_LIMIT.TIER_2; - const LIMIT_DURATION = - (ConfigService.get('LIMIT_DURATION') as unknown as number) || relayConstants.DEFAULT_RATE_LIMIT.DURATION; + const TIER_2_RATE_LIMIT = ConfigService.get('TIER_2_RATE_LIMIT'); + const LIMIT_DURATION = ConfigService.get('LIMIT_DURATION'); describe('RPC Rate Limiter Acceptance Tests', () => { const sendMultipleRequests = async (method: string, params: any[], threshold: number) => { diff --git a/packages/server/tests/acceptance/rpc_batch1.spec.ts b/packages/server/tests/acceptance/rpc_batch1.spec.ts index 1c192247d4..d1ade0ea0c 100644 --- a/packages/server/tests/acceptance/rpc_batch1.spec.ts +++ b/packages/server/tests/acceptance/rpc_batch1.spec.ts @@ -73,7 +73,7 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { let account2Address: string; let expectedGasPrice: string; - const CHAIN_ID = (ConfigService.get('CHAIN_ID') as string) || '0x12a'; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const requestId = 'rpc_batch1Test'; const requestIdPrefix = Utils.formatRequestIdMessage(requestId); const requestDetails = JSON.stringify(new RequestDetails({ requestId: 'rpc_batch1Test', ipAddress: '0.0.0.0' })); @@ -84,9 +84,9 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { const TEN_HBAR = Utils.add0xPrefix( (BigInt(new Hbar(10).toTinybars().toString()) * BigInt(Constants.TINYBAR_TO_WEIBAR_COEF)).toString(16), ); - const gasPriceDeviation = parseFloat((ConfigService.get('TEST_GAS_PRICE_DEVIATION') ?? '0.2') as string); + const gasPriceDeviation = ConfigService.get('TEST_GAS_PRICE_DEVIATION'); const sendRawTransaction = relay.sendRawTransaction; - const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING') as boolean; + const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING'); /** * resolves long zero addresses to EVM addresses by querying mirror node @@ -356,15 +356,15 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { }); it('should be able to use `address` param with a large block range', async () => { - const blockRangeLimit = Constants.DEFAULT_ETH_GET_LOGS_BLOCK_RANGE_LIMIT; - Constants.DEFAULT_ETH_GET_LOGS_BLOCK_RANGE_LIMIT = 10; + const blockRangeLimit = ConfigService.get('ETH_GET_LOGS_BLOCK_RANGE_LIMIT'); + let customBlockRangeLimit = 10; try { //when we pass only address, it defaults to the latest block const logs = await relay.call( RelayCalls.ETH_ENDPOINTS.ETH_GET_LOGS, [ { - fromBlock: numberTo0x(latestBlock - Constants.DEFAULT_ETH_GET_LOGS_BLOCK_RANGE_LIMIT - 1), + fromBlock: numberTo0x(latestBlock - customBlockRangeLimit - 1), address: contractAddress, }, ], @@ -376,7 +376,7 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { expect(logs[i].address.toLowerCase()).to.equal(contractAddress.toLowerCase()); } } finally { - Constants.DEFAULT_ETH_GET_LOGS_BLOCK_RANGE_LIMIT = blockRangeLimit; + customBlockRangeLimit = blockRangeLimit; } }); @@ -1381,7 +1381,10 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { }; const signedTx = await accounts[1].wallet.signTransaction(transaction); - const error = predefined.TRANSACTION_SIZE_TOO_BIG('132320', String(Constants.SEND_RAW_TRANSACTION_SIZE_LIMIT)); + const error = predefined.TRANSACTION_SIZE_TOO_BIG( + '132320', + String(ConfigService.get('SEND_RAW_TRANSACTION_SIZE_LIMIT')), + ); await Assertions.assertPredefinedRpcError(error, sendRawTransaction, true, relay, [signedTx, requestDetails]); }); diff --git a/packages/server/tests/acceptance/rpc_batch2.spec.ts b/packages/server/tests/acceptance/rpc_batch2.spec.ts index b64b131399..a075c0a262 100644 --- a/packages/server/tests/acceptance/rpc_batch2.spec.ts +++ b/packages/server/tests/acceptance/rpc_batch2.spec.ts @@ -79,7 +79,7 @@ describe('@api-batch-2 RPC Server Acceptance Tests', function () { let createChildTx: ethers.ContractTransactionResponse; let accounts0StartBalance: bigint; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || 0; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const ONE_TINYBAR = Utils.add0xPrefix(Utils.toHex(ethers.parseUnits('1', 10))); const ONE_WEIBAR = Utils.add0xPrefix(Utils.toHex(ethers.parseUnits('1', 18))); diff --git a/packages/server/tests/acceptance/rpc_batch3.spec.ts b/packages/server/tests/acceptance/rpc_batch3.spec.ts index 6528df9e08..c3b1e597a2 100644 --- a/packages/server/tests/acceptance/rpc_batch3.spec.ts +++ b/packages/server/tests/acceptance/rpc_batch3.spec.ts @@ -74,7 +74,7 @@ describe('@api-batch-3 RPC Server Acceptance Tests', function () { let mirrorPrimaryAccount: ethers.Wallet; let mirrorSecondaryAccount: ethers.Wallet; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || 0x12a; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const ONE_TINYBAR = Utils.add0xPrefix(Utils.toHex(ethers.parseUnits('1', 10))); let reverterContract: ethers.Contract; @@ -611,7 +611,7 @@ describe('@api-batch-3 RPC Server Acceptance Tests', function () { }; // Since we want the http status code, we need to perform the call using a client http request instead of using the relay instance directly - const testClientPort = ConfigService.get('E2E_SERVER_PORT') || '7546'; + const testClientPort = ConfigService.get('E2E_SERVER_PORT'); const testClient = Axios.create({ baseURL: 'http://localhost:' + testClientPort, responseType: 'json' as const, @@ -797,7 +797,7 @@ describe('@api-batch-3 RPC Server Acceptance Tests', function () { let initialEthCallSelectorsAlwaysToConsensus: any, hrc719Contract: ethers.Contract; before(async () => { - initialEthCallSelectorsAlwaysToConsensus = ConfigService.get('ETH_CALL_CONSENSUS_SELECTORS'); + initialEthCallSelectorsAlwaysToConsensus = JSON.parse(ConfigService.get('ETH_CALL_CONSENSUS_SELECTORS')); hrc719Contract = await Utils.deployContract( HRC719ContractJson.abi, @@ -814,8 +814,8 @@ describe('@api-batch-3 RPC Server Acceptance Tests', function () { }); it('should NOT allow eth_call to process IHRC719.isAssociated() method', async () => { - const selectorsList = ConfigService.get('ETH_CALL_CONSENSUS_SELECTORS'); - expect(selectorsList).to.be.undefined; + const selectorsList = JSON.parse(ConfigService.get('ETH_CALL_CONSENSUS_SELECTORS')); + expect(selectorsList.length).to.eq(0); // If the selector for `isAssociated` is not included in `ETH_CALL_CONSENSUS_SELECTORS`, the request will fail with a `CALL_EXCEPTION` error code. await expect(hrc719Contract.isAssociated(tokenAddress)).to.eventually.be.rejected.and.have.property( diff --git a/packages/server/tests/acceptance/serverConfig.spec.ts b/packages/server/tests/acceptance/serverConfig.spec.ts index a9c4086dc7..e342f40ecc 100644 --- a/packages/server/tests/acceptance/serverConfig.spec.ts +++ b/packages/server/tests/acceptance/serverConfig.spec.ts @@ -17,16 +17,17 @@ * limitations under the License. * */ +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { expect } from 'chai'; + import { Utils } from '../helpers/utils'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; describe('@server-config Server Configuration Options Coverage', function () { describe('Koa Server Timeout', () => { it('should timeout a request after the specified time', async () => { - const requestTimeoutMs: number = parseInt(ConfigService.get('SERVER_REQUEST_TIMEOUT_MS') || '3000'); + const requestTimeoutMs: number = ConfigService.get('SERVER_REQUEST_TIMEOUT_MS'); const host = ConfigService.get('SERVER_HOST') || 'localhost'; - const port = parseInt(ConfigService.get('SERVER_PORT') || '7546'); + const port = ConfigService.get('SERVER_PORT'); const method = 'eth_blockNumber'; const params: any[] = []; diff --git a/packages/server/tests/helpers/assertions.ts b/packages/server/tests/helpers/assertions.ts index 3e78024896..574369f99f 100644 --- a/packages/server/tests/helpers/assertions.ts +++ b/packages/server/tests/helpers/assertions.ts @@ -42,7 +42,7 @@ export default class Assertions { static maxBlockGasLimit = 30_000_000; static defaultGasUsed = 0.5; - public static readonly gasPriceDeviation = parseFloat(ConfigService.get('TEST_GAS_PRICE_DEVIATION') ?? '0.2'); + public static readonly gasPriceDeviation = ConfigService.get('TEST_GAS_PRICE_DEVIATION'); static assertId = (id) => { const [shard, realm, num] = id.split('.'); diff --git a/packages/server/tests/integration/server.spec.ts b/packages/server/tests/integration/server.spec.ts index 4b40136921..1bf2752371 100644 --- a/packages/server/tests/integration/server.spec.ts +++ b/packages/server/tests/integration/server.spec.ts @@ -19,19 +19,18 @@ */ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; + import { ConfigServiceTestHelper } from '../../../config-service/tests/configServiceTestHelper'; ConfigServiceTestHelper.appendEnvsFromPath(__dirname + '/test.env'); +import { predefined, RelayImpl } from '@hashgraph/json-rpc-relay'; +import { MirrorNodeClient } from '@hashgraph/json-rpc-relay/dist/lib/clients'; import Axios, { AxiosInstance } from 'axios'; import { expect } from 'chai'; -import sinon from 'sinon'; import { Server } from 'http'; +import Koa from 'koa'; +import sinon from 'sinon'; import { GCProfiler } from 'v8'; -import Assertions from '../helpers/assertions'; -import { TracerType, Validator } from '../../src/validator'; -import RelayCalls from '../../tests/helpers/constants'; -import * as Constants from '../../src/validator/constants'; -import { Utils } from '../helpers/utils'; -import { predefined, RelayImpl } from '@hashgraph/json-rpc-relay'; + import { contractAddress1, contractAddress2, @@ -40,8 +39,11 @@ import { overrideEnvsInMochaDescribe, withOverriddenEnvsInMochaTest, } from '../../../relay/tests/helpers'; -import { MirrorNodeClient } from '@hashgraph/json-rpc-relay/dist/lib/clients'; -import Koa from 'koa'; +import { TracerType, Validator } from '../../src/validator'; +import * as Constants from '../../src/validator/constants'; +import RelayCalls from '../../tests/helpers/constants'; +import Assertions from '../helpers/assertions'; +import { Utils } from '../helpers/utils'; const MISSING_PARAM_ERROR = 'Missing value for required parameter'; @@ -118,7 +120,7 @@ describe('RPC Server', function () { }); BaseTest.defaultResponseChecks(res); - expect(res.data.result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(res.data.result).to.be.equal(ConfigService.get('CHAIN_ID')); }); it('validates enforcement of request id', async function () { @@ -157,7 +159,7 @@ describe('RPC Server', function () { expect(response.data, "Default response: 'data' should have 'result' property").to.have.property('result'); expect(response.data.id, "Default response: 'data.id' should equal '2'").to.be.equal('2'); expect(response.data.jsonrpc, "Default response: 'data.jsonrpc' should equal '2.0'").to.be.equal('2.0'); - expect(response.data.result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data.result).to.be.equal(ConfigService.get('CHAIN_ID')); } catch (error: any) { expect(true, `Unexpected error: ${error.message}`).to.eq(false); } finally { @@ -541,7 +543,7 @@ describe('RPC Server', function () { // verify response for each request for (let i = 0; i < response.data.length; i++) { expect(response.data[i].id).to.be.equal((i + 2).toString()); - expect(response.data[i].result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data[i].result).to.be.equal(ConfigService.get('CHAIN_ID')); } }); @@ -558,14 +560,14 @@ describe('RPC Server', function () { // verify response for each result expect(response.data[0].id).to.be.equal('2'); - expect(response.data[0].result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data[0].result).to.be.equal(ConfigService.get('CHAIN_ID')); // verify eth_accounts result expect(response.data[1].id).to.be.equal('3'); expect(response.data[1].result).to.be.an('Array'); expect(response.data[1].result.length).to.be.equal(0); // verify eth_chainId result expect(response.data[2].id).to.be.equal('4'); - expect(response.data[2].result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data[2].result).to.be.equal(ConfigService.get('CHAIN_ID')); }); it('should execute "eth_chainId" and "eth_accounts" in batch request with invalid request id', async function () { @@ -576,7 +578,7 @@ describe('RPC Server', function () { // verify response for each result expect(response.data[0].id).to.be.equal('2'); - expect(response.data[0].result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data[0].result).to.be.equal(ConfigService.get('CHAIN_ID')); // verify eth_accounts result expect(response.data[1].id).to.be.equal(null); expect(response.data[1].error).to.be.an('Object'); @@ -596,7 +598,7 @@ describe('RPC Server', function () { // verify eth_chainId result on position 0 expect(response.data[0].id).to.be.equal('2'); - expect(response.data[0].result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data[0].result).to.be.equal(ConfigService.get('CHAIN_ID')); // verify method not found error on position 1 expect(response.data[1].id).to.be.equal('3'); expect(response.data[1].error).to.be.an('Object'); @@ -604,7 +606,7 @@ describe('RPC Server', function () { expect(response.data[1].error.message).to.be.equal('Method non_existent_method not found'); // verify eth_chainId result on position 2 expect(response.data[2].id).to.be.equal('4'); - expect(response.data[2].result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data[2].result).to.be.equal(ConfigService.get('CHAIN_ID')); }); it('should execute "eth_chainId" and method not found and params error in batch request', async function () { @@ -624,7 +626,7 @@ describe('RPC Server', function () { // verify eth_chainId result on position 0 expect(response.data[0].id).to.be.equal('2'); - expect(response.data[0].result).to.be.equal('0x' + Number(ConfigService.get('CHAIN_ID')).toString(16)); + expect(response.data[0].result).to.be.equal(ConfigService.get('CHAIN_ID')); // verify method not found error on position 1 expect(response.data[1].id).to.be.equal('3'); expect(response.data[1].error).to.be.an('Object'); @@ -668,13 +670,20 @@ describe('RPC Server', function () { }); withOverriddenEnvsInMochaTest({ BATCH_REQUESTS_ENABLED: undefined }, async function () { - it('batch request be disabled by default', async function () { - try { - await testClient.post('/', [getEthChainIdRequest(2), getEthAccountsRequest(3), getEthChainIdRequest(4)]); - Assertions.expectedError(); - } catch (error: any) { - BaseTest.batchDisabledErrorCheck(error.response); - } + it('batch request should be enabled by default', async function () { + const response = await testClient.post('/', [getEthChainIdRequest(2), getEthAccountsRequest(null)]); + + // verify response + BaseTest.baseDefaultResponseChecks(response); + + // verify response for each result + expect(response.data[0].id).to.be.equal('2'); + expect(response.data[0].result).to.be.equal(ConfigService.get('CHAIN_ID')); + // verify eth_accounts result + expect(response.data[1].id).to.be.equal(null); + expect(response.data[1].error).to.be.an('Object'); + expect(response.data[1].error.code).to.be.equal(-32600); + expect(response.data[1].error.message).to.be.equal('Invalid Request'); }); }); }); diff --git a/packages/ws-server/src/metrics/connectionLimiter.ts b/packages/ws-server/src/metrics/connectionLimiter.ts index 53ddac241f..9c6ac0dae8 100644 --- a/packages/ws-server/src/metrics/connectionLimiter.ts +++ b/packages/ws-server/src/metrics/connectionLimiter.ts @@ -88,10 +88,7 @@ export default class ConnectionLimiter { registers: [register], }); - const rateLimitDuration = ConfigService.get('LIMIT_DURATION') - ? // @ts-ignore - parseInt(ConfigService.get('LIMIT_DURATION')) - : constants.DEFAULT_RATE_LIMIT.DURATION; + const rateLimitDuration = ConfigService.get('LIMIT_DURATION'); this.rateLimit = new RateLimit(logger.child({ name: 'ip-rate-limit' }), register, rateLimitDuration); } @@ -126,9 +123,8 @@ export default class ConnectionLimiter { public applyLimits(ctx) { // Limit total connections - const MAX_CONNECTION_LIMIT = ConfigService.get('WS_CONNECTION_LIMIT') || '10'; - // @ts-ignore - if (this.connectedClients > parseInt(MAX_CONNECTION_LIMIT)) { + const MAX_CONNECTION_LIMIT = ConfigService.get('WS_CONNECTION_LIMIT'); + if (this.connectedClients > MAX_CONNECTION_LIMIT) { this.logger.info( `Closing connection ${ctx.websocket.id} due to exceeded maximum connections (max_con=${MAX_CONNECTION_LIMIT})`, ); @@ -153,9 +149,8 @@ export default class ConnectionLimiter { // Limit connections from a single IP address const { ip } = ctx.request; - const MAX_CONNECTION_LIMIT_PER_IP = ConfigService.get('WS_CONNECTION_LIMIT_PER_IP') || '10'; - // @ts-ignore - if (this.clientIps[ip] && this.clientIps[ip] > parseInt(MAX_CONNECTION_LIMIT_PER_IP)) { + const MAX_CONNECTION_LIMIT_PER_IP = ConfigService.get('WS_CONNECTION_LIMIT_PER_IP'); + if (this.clientIps[ip] && this.clientIps[ip] > MAX_CONNECTION_LIMIT_PER_IP) { this.logger.info( `Closing connection ${ctx.websocket.id} due to exceeded maximum connections from a single IP: address ${ip} - ${this.clientIps[ip]} connections. (max_con=${MAX_CONNECTION_LIMIT_PER_IP})`, ); @@ -191,14 +186,12 @@ export default class ConnectionLimiter { } public validateSubscriptionLimit(ctx) { - // @ts-ignore - return ctx.websocket.subscriptions < parseInt(ConfigService.get('WS_SUBSCRIPTION_LIMIT') || '10'); + return ctx.websocket.subscriptions < ConfigService.get('WS_SUBSCRIPTION_LIMIT'); } // Starts a timeout timer that closes the connection public startInactivityTTLTimer(websocket) { - // @ts-ignore - const maxInactivityTTL = parseInt(ConfigService.get('WS_MAX_INACTIVITY_TTL') || '300000'); + const maxInactivityTTL = ConfigService.get('WS_MAX_INACTIVITY_TTL'); websocket.inactivityTTL = setTimeout(() => { if (websocket.readyState !== 3) { // 3 = CLOSED, Avoid closing already closed connections diff --git a/packages/ws-server/src/utils/utils.ts b/packages/ws-server/src/utils/utils.ts index 108bbe2f64..f91b255017 100644 --- a/packages/ws-server/src/utils/utils.ts +++ b/packages/ws-server/src/utils/utils.ts @@ -143,8 +143,7 @@ export const resolveParams = (method: string, params: any): any[] => { * @returns {boolean} Returns true if multiple addresses are enabled, otherwise returns false. */ export const getMultipleAddressesEnabled = (): boolean => { - // @ts-ignore - return ConfigService.get('WS_MULTIPLE_ADDRESSES_ENABLED') ?? false; + return ConfigService.get('WS_MULTIPLE_ADDRESSES_ENABLED'); }; /** @@ -152,8 +151,7 @@ export const getMultipleAddressesEnabled = (): boolean => { * @returns {boolean} A boolean indicating whether WebSocket batch requests are enabled. */ export const getWsBatchRequestsEnabled = (): boolean => { - // @ts-ignore - return ConfigService.get('WS_BATCH_REQUESTS_ENABLED') ?? true; + return ConfigService.get('WS_BATCH_REQUESTS_ENABLED'); }; /** @@ -161,7 +159,7 @@ export const getWsBatchRequestsEnabled = (): boolean => { * @returns {number} The maximum size of batch requests for WebSocket. */ export const getBatchRequestsMaxSize = (): number => { - return Number(ConfigService.get('WS_BATCH_REQUESTS_MAX_SIZE') ?? 20); + return ConfigService.get('WS_BATCH_REQUESTS_MAX_SIZE'); }; /** diff --git a/packages/ws-server/src/webSocketServer.ts b/packages/ws-server/src/webSocketServer.ts index 7f4f5b3a77..a39fc7fa77 100644 --- a/packages/ws-server/src/webSocketServer.ts +++ b/packages/ws-server/src/webSocketServer.ts @@ -18,26 +18,27 @@ * */ +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { JsonRpcError, predefined, Relay, RelayImpl } from '@hashgraph/json-rpc-relay/dist'; +import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; +import KoaJsonRpc from '@hashgraph/json-rpc-server/dist/koaJsonRpc'; +import { IJsonRpcRequest } from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/IJsonRpcRequest'; +import jsonResp from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/RpcResponse'; import Koa from 'koa'; -import pino from 'pino'; -import { v4 as uuid } from 'uuid'; import websockify from 'koa-websocket'; +import pino from 'pino'; import { collectDefaultMetrics, Registry } from 'prom-client'; +import { v4 as uuid } from 'uuid'; + import { getRequestResult } from './controllers'; -import { WS_CONSTANTS } from './utils/constants'; -import WsMetricRegistry from './metrics/wsMetricRegistry'; import ConnectionLimiter from './metrics/connectionLimiter'; -import KoaJsonRpc from '@hashgraph/json-rpc-server/dist/koaJsonRpc'; -import jsonResp from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/RpcResponse'; -import { JsonRpcError, predefined, Relay, RelayImpl } from '@hashgraph/json-rpc-relay/dist'; +import WsMetricRegistry from './metrics/wsMetricRegistry'; +import { WS_CONSTANTS } from './utils/constants'; import { getBatchRequestsMaxSize, getWsBatchRequestsEnabled, handleConnectionClose, sendToClient } from './utils/utils'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import { IJsonRpcRequest } from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/IJsonRpcRequest'; -import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; const mainLogger = pino({ name: 'hedera-json-rpc-relay', - // @ts-ignore + // Pino requires the default level to be explicitly set; without fallback value ("trace"), an invalid or missing value could trigger the "default level must be included in custom levels" error. level: ConfigService.get('LOG_LEVEL') || 'trace', transport: { target: 'pino-pretty', @@ -55,7 +56,7 @@ const mirrorNodeClient = relay.mirrorClient(); const limiter = new ConnectionLimiter(logger, register); const wsMetricRegistry = new WsMetricRegistry(register); -const pingInterval = Number(ConfigService.get('WS_PING_INTERVAL') || 100000); +const pingInterval = ConfigService.get('WS_PING_INTERVAL'); const app = websockify(new Koa()); app.ws.use(async (ctx: Koa.Context) => { diff --git a/packages/ws-server/tests/acceptance/batchRequest.spec.ts b/packages/ws-server/tests/acceptance/batchRequest.spec.ts index 9295708856..0a55083ae7 100644 --- a/packages/ws-server/tests/acceptance/batchRequest.spec.ts +++ b/packages/ws-server/tests/acceptance/batchRequest.spec.ts @@ -19,11 +19,12 @@ */ // external resources +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { predefined } from '@hashgraph/json-rpc-relay/dist'; import { expect } from 'chai'; import { ethers, WebSocketProvider } from 'ethers'; + import { WsTestConstant, WsTestHelper } from '../helper'; -import { predefined } from '@hashgraph/json-rpc-relay/dist'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; describe('@web-socket-batch-request Batch Requests', async function () { const METHOD_NAME = 'batch_request'; diff --git a/packages/ws-server/tests/acceptance/getTransactionByHash.spec.ts b/packages/ws-server/tests/acceptance/getTransactionByHash.spec.ts index 4b1f4d0a9c..95025e2caf 100644 --- a/packages/ws-server/tests/acceptance/getTransactionByHash.spec.ts +++ b/packages/ws-server/tests/acceptance/getTransactionByHash.spec.ts @@ -19,21 +19,22 @@ */ // external resources -import { expect } from 'chai'; -import { ethers, WebSocketProvider } from 'ethers'; -import { WsTestConstant, WsTestHelper } from '../helper'; +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { numberTo0x } from '@hashgraph/json-rpc-relay/dist/formatters'; +import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; import { ONE_TINYBAR_IN_WEI_HEX } from '@hashgraph/json-rpc-relay/tests/lib/eth/eth-config'; -import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; -import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import MirrorClient from '@hashgraph/json-rpc-server/tests/clients/mirrorClient'; import RelayClient from '@hashgraph/json-rpc-server/tests/clients/relayClient'; -import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; +import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; +import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; +import { expect } from 'chai'; +import { ethers, WebSocketProvider } from 'ethers'; + +import { WsTestConstant, WsTestHelper } from '../helper'; describe('@web-socket-batch-2 eth_getTransactionByHash', async function () { const METHOD_NAME = 'eth_getTransactionByHash'; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || '0x12a'; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const INVALID_PARAMS = [ [], [''], diff --git a/packages/ws-server/tests/acceptance/getTransactionCount.spec.ts b/packages/ws-server/tests/acceptance/getTransactionCount.spec.ts index 278f6cf97f..25ceb5129a 100644 --- a/packages/ws-server/tests/acceptance/getTransactionCount.spec.ts +++ b/packages/ws-server/tests/acceptance/getTransactionCount.spec.ts @@ -19,20 +19,21 @@ */ // external resources -import { expect } from 'chai'; -import { ethers, WebSocketProvider } from 'ethers'; -import { WsTestConstant, WsTestHelper } from '../helper'; -import { numberTo0x } from '@hashgraph/json-rpc-relay/dist/formatters'; -import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; -import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { numberTo0x } from '@hashgraph/json-rpc-relay/dist/formatters'; +import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; import MirrorClient from '@hashgraph/json-rpc-server/tests/clients/mirrorClient'; import RelayClient from '@hashgraph/json-rpc-server/tests/clients/relayClient'; -import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; +import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; +import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; +import { expect } from 'chai'; +import { ethers, WebSocketProvider } from 'ethers'; + +import { WsTestConstant, WsTestHelper } from '../helper'; describe('@release @web-socket-batch-2 eth_getTransactionCount', async function () { const METHOD_NAME = 'eth_getTransactionCount'; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || '0x12a'; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const ONE_TINYBAR = Utils.add0xPrefix(Utils.toHex(ethers.parseUnits('1', 10))); // @ts-ignore diff --git a/packages/ws-server/tests/acceptance/getTransactionReceipt.spec.ts b/packages/ws-server/tests/acceptance/getTransactionReceipt.spec.ts index be26f3061b..bed8262d3b 100644 --- a/packages/ws-server/tests/acceptance/getTransactionReceipt.spec.ts +++ b/packages/ws-server/tests/acceptance/getTransactionReceipt.spec.ts @@ -19,21 +19,22 @@ */ // external resources -import { expect } from 'chai'; -import { ethers, WebSocketProvider } from 'ethers'; -import { WsTestConstant, WsTestHelper } from '../helper'; +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { numberTo0x } from '@hashgraph/json-rpc-relay/dist/formatters'; +import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; import { ONE_TINYBAR_IN_WEI_HEX } from '@hashgraph/json-rpc-relay/tests/lib/eth/eth-config'; -import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; -import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import MirrorClient from '@hashgraph/json-rpc-server/tests/clients/mirrorClient'; import RelayClient from '@hashgraph/json-rpc-server/tests/clients/relayClient'; -import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; +import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; +import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; +import { expect } from 'chai'; +import { ethers, WebSocketProvider } from 'ethers'; + +import { WsTestConstant, WsTestHelper } from '../helper'; describe('@web-socket-batch-2 eth_getTransactionReceipt', async function () { const METHOD_NAME = 'eth_getTransactionReceipt'; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || '0x12a'; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const INVALID_PARAMS = [ [], [''], diff --git a/packages/ws-server/tests/acceptance/index.spec.ts b/packages/ws-server/tests/acceptance/index.spec.ts index 60b91eb004..9d6330fda7 100644 --- a/packages/ws-server/tests/acceptance/index.spec.ts +++ b/packages/ws-server/tests/acceptance/index.spec.ts @@ -23,10 +23,10 @@ import dotenv from 'dotenv'; import path from 'path'; dotenv.config({ path: path.resolve(__dirname, '../../../../.env') }); -import { Server } from 'node:http'; - import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import constants from '@hashgraph/json-rpc-relay/dist/lib/constants'; +import { Server } from 'node:http'; + import { setServerTimeout } from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/utils'; import app from '@hashgraph/json-rpc-server/dist/server'; import MirrorClient from '@hashgraph/json-rpc-server/tests/clients/mirrorClient'; @@ -48,7 +48,7 @@ describe('RPC Server Acceptance Tests', function () { const testLogger = pino({ name: 'hedera-json-rpc-relay', - level: (ConfigService.get('LOG_LEVEL') as string) || 'trace', + level: ConfigService.get('LOG_LEVEL'), transport: { target: 'pino-pretty', options: { @@ -59,13 +59,13 @@ describe('RPC Server Acceptance Tests', function () { }); const logger = testLogger.child({ name: 'rpc-acceptance-test' }); - const NETWORK = ConfigService.get('HEDERA_NETWORK') as string; - const OPERATOR_KEY = ConfigService.get('OPERATOR_KEY_MAIN') as string; - const OPERATOR_ID = ConfigService.get('OPERATOR_ID_MAIN') as string; - const MIRROR_NODE_URL = ConfigService.get('MIRROR_NODE_URL') as string; + const NETWORK = ConfigService.get('HEDERA_NETWORK'); + const OPERATOR_KEY = ConfigService.get('OPERATOR_KEY_MAIN'); + const OPERATOR_ID = ConfigService.get('OPERATOR_ID_MAIN'); + const MIRROR_NODE_URL = ConfigService.get('MIRROR_NODE_URL'); const LOCAL_RELAY_URL = 'http://localhost:7546'; - const RELAY_URL = ConfigService.get('E2E_RELAY_HOST') || LOCAL_RELAY_URL; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || '0x12a'; + const RELAY_URL = ConfigService.get('E2E_RELAY_HOST'); + const CHAIN_ID = ConfigService.get('CHAIN_ID'); global.relayIsLocal = RELAY_URL === LOCAL_RELAY_URL; global.servicesNode = new ServicesClient( diff --git a/packages/ws-server/tests/acceptance/rateLimiter.spec.ts b/packages/ws-server/tests/acceptance/rateLimiter.spec.ts index 1607c5fa4a..f93b21b2a4 100644 --- a/packages/ws-server/tests/acceptance/rateLimiter.spec.ts +++ b/packages/ws-server/tests/acceptance/rateLimiter.spec.ts @@ -19,17 +19,18 @@ */ // external resources -import { expect } from 'chai'; -import { WsTestHelper } from '../helper'; +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import relayConstants from '@hashgraph/json-rpc-relay/dist/lib/constants'; -import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; import { IPRateLimitExceeded } from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/RpcError'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; +import { expect } from 'chai'; + import { ConfigServiceTestHelper } from '../../../config-service/tests/configServiceTestHelper'; +import { WsTestHelper } from '../helper'; describe('@web-socket-ratelimiter Rate Limit Tests', async function () { - const rateLimitTier2 = Number(ConfigService.get('TIER_2_RATE_LIMIT') || relayConstants.DEFAULT_RATE_LIMIT.TIER_2); - const limitDuration = Number(ConfigService.get('LIMIT_DURATION')) || relayConstants.DEFAULT_RATE_LIMIT.DURATION; + const rateLimitTier2 = ConfigService.get('TIER_2_RATE_LIMIT'); + const limitDuration = ConfigService.get('LIMIT_DURATION'); const batchRequests = [ { diff --git a/packages/ws-server/tests/acceptance/sendRawTransaction.spec.ts b/packages/ws-server/tests/acceptance/sendRawTransaction.spec.ts index bda0c5f2d4..66d378402c 100644 --- a/packages/ws-server/tests/acceptance/sendRawTransaction.spec.ts +++ b/packages/ws-server/tests/acceptance/sendRawTransaction.spec.ts @@ -19,23 +19,24 @@ */ // external resources -import { expect } from 'chai'; -import { ethers, WebSocketProvider } from 'ethers'; -import { WsTestConstant, WsTestHelper } from '../helper'; +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { predefined } from '@hashgraph/json-rpc-relay/dist'; -import constants from '@hashgraph/json-rpc-relay/dist/lib/constants'; import { numberTo0x } from '@hashgraph/json-rpc-relay/dist/formatters'; -import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; -import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; +import constants from '@hashgraph/json-rpc-relay/dist/lib/constants'; +import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; import { ONE_TINYBAR_IN_WEI_HEX } from '@hashgraph/json-rpc-relay/tests/lib/eth/eth-config'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import MirrorClient from '@hashgraph/json-rpc-server/tests/clients/mirrorClient'; import RelayClient from '@hashgraph/json-rpc-server/tests/clients/relayClient'; -import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; +import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; +import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; +import { expect } from 'chai'; +import { ethers, WebSocketProvider } from 'ethers'; + +import { WsTestConstant, WsTestHelper } from '../helper'; describe('@web-socket-batch-2 eth_sendRawTransaction', async function () { const METHOD_NAME = 'eth_sendRawTransaction'; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || '0x12a'; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const INVALID_PARAMS = [ [], [''], diff --git a/packages/ws-server/tests/acceptance/subscribe.spec.ts b/packages/ws-server/tests/acceptance/subscribe.spec.ts index 479705e632..563443b2d4 100644 --- a/packages/ws-server/tests/acceptance/subscribe.spec.ts +++ b/packages/ws-server/tests/acceptance/subscribe.spec.ts @@ -19,20 +19,21 @@ */ // external resources -import WebSocket from 'ws'; -import { ethers } from 'ethers'; -import chai, { expect } from 'chai'; -import { WsTestHelper } from '../helper'; -import { solidity } from 'ethereum-waffle'; -import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; -import Constants from '@hashgraph/json-rpc-server/tests/helpers/constants'; +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { predefined, WebSocketError } from '@hashgraph/json-rpc-relay/dist'; +import LogContractJson from '@hashgraph/json-rpc-server/tests/contracts/Logs.json'; +import IERC20Json from '@hashgraph/json-rpc-server/tests/contracts/openzeppelin/IERC20.json'; import Assertions from '@hashgraph/json-rpc-server/tests/helpers/assertions'; import assertions from '@hashgraph/json-rpc-server/tests/helpers/assertions'; -import LogContractJson from '@hashgraph/json-rpc-server/tests/contracts/Logs.json'; +import Constants from '@hashgraph/json-rpc-server/tests/helpers/constants'; +import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils'; import { AliasAccount } from '@hashgraph/json-rpc-server/tests/types/AliasAccount'; -import IERC20Json from '@hashgraph/json-rpc-server/tests/contracts/openzeppelin/IERC20.json'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import chai, { expect } from 'chai'; +import { solidity } from 'ethereum-waffle'; +import { ethers } from 'ethers'; +import WebSocket from 'ws'; + +import { WsTestHelper } from '../helper'; chai.use(solidity); @@ -73,8 +74,9 @@ const createLogs = async (contract: ethers.Contract, requestId) => { describe('@web-socket-batch-3 eth_subscribe', async function () { this.timeout(240 * 1000); // 240 seconds - const CHAIN_ID = ConfigService.get('CHAIN_ID') || 0; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); let server; + // @ts-ignore const { servicesNode, relay, mirrorNode } = global; @@ -435,12 +437,12 @@ describe('@web-socket-batch-3 eth_subscribe', async function () { // We already have one connection expect(server._connections).to.equal(1); - for (let i = 1; i < parseInt(ConfigService.get('WS_CONNECTION_LIMIT')); i++) { + for (let i = 1; i < ConfigService.get('WS_CONNECTION_LIMIT'); i++) { providers.push(await establishConnection()); } // Server is at max connections - expect(server._connections).to.equal(parseInt(ConfigService.get('WS_CONNECTION_LIMIT'))); + expect(server._connections).to.equal(ConfigService.get('WS_CONNECTION_LIMIT')); }); afterEach(async () => { @@ -499,7 +501,7 @@ describe('@web-socket-batch-3 eth_subscribe', async function () { expect(message.toString('utf8')).to.equal(WebSocketError.TTL_EXPIRED.message); }); - await new Promise((resolve) => setTimeout(resolve, parseInt(ConfigService.get('WS_MAX_INACTIVITY_TTL')) + 1000)); + await new Promise((resolve) => setTimeout(resolve, ConfigService.get('WS_MAX_INACTIVITY_TTL') + 1000)); expect(closeEventHandled2).to.eq(true); expect(closeEventHandled3).to.eq(true); @@ -892,12 +894,11 @@ describe('@web-socket-batch-3 eth_subscribe', async function () { WsTestHelper.overrideEnvsInMochaDescribe({ WS_CONNECTION_LIMIT_PER_IP: 3 }); it('Does not allow more connections from the same IP than the specified limit', async function () { - const providers = []; + const providers: any[] = []; // Creates the maximum allowed connections - // @ts-ignore - for (let i = 1; i < parseInt(ConfigService.get('WS_CONNECTION_LIMIT_PER_IP')); i++) { - // @ts-ignore + + for (let i = 1; i < ConfigService.get('WS_CONNECTION_LIMIT_PER_IP'); i++) { providers.push(await new ethers.WebSocketProvider(WS_RELAY_URL)); } @@ -905,14 +906,13 @@ describe('@web-socket-batch-3 eth_subscribe', async function () { // Repeat the following several times to make sure the internal counters are consistently correct for (let i = 0; i < 3; i++) { - // @ts-ignore - expect(server._connections).to.equal(parseInt(ConfigService.get('WS_CONNECTION_LIMIT_PER_IP'))); + expect(server._connections).to.equal(ConfigService.get('WS_CONNECTION_LIMIT_PER_IP')); // The next connection should be closed by the server const provider = await new ethers.WebSocketProvider(WS_RELAY_URL); let closeEventHandled = false; - // @ts-ignore + provider.websocket.on('close', (code, message) => { closeEventHandled = true; expect(code).to.equal(WebSocketError.CONNECTION_IP_LIMIT_EXCEEDED.code); @@ -920,8 +920,8 @@ describe('@web-socket-batch-3 eth_subscribe', async function () { }); await new Promise((resolve) => setTimeout(resolve, 1000)); - // @ts-ignore - expect(server._connections).to.equal(parseInt(ConfigService.get('WS_CONNECTION_LIMIT_PER_IP'))); + + expect(server._connections).to.equal(ConfigService.get('WS_CONNECTION_LIMIT_PER_IP')); expect(closeEventHandled).to.eq(true); await new Promise((resolve) => setTimeout(resolve, 1000)); diff --git a/packages/ws-server/tests/acceptance/subscribeNewHeads.spec.ts b/packages/ws-server/tests/acceptance/subscribeNewHeads.spec.ts index 5c207aaa0d..b0826377f0 100644 --- a/packages/ws-server/tests/acceptance/subscribeNewHeads.spec.ts +++ b/packages/ws-server/tests/acceptance/subscribeNewHeads.spec.ts @@ -99,7 +99,7 @@ function verifyResponse(response: any, done: Mocha.Done, webSocket: any, include describe('@web-socket-batch-3 eth_subscribe newHeads', async function () { this.timeout(240 * 1000); // 240 seconds const accounts: AliasAccount[] = []; - const CHAIN_ID = ConfigService.get('CHAIN_ID') || 0; + const CHAIN_ID = ConfigService.get('CHAIN_ID'); const ONE_TINYBAR = Utils.add0xPrefix(Utils.toHex(ethers.parseUnits('1', 10))); let mirrorNodeServer, requestId, rpcServer, wsServer; @@ -194,9 +194,9 @@ describe('@web-socket-batch-3 eth_subscribe newHeads', async function () { }); }); - WsTestHelper.withOverriddenEnvsInMochaTest({ WS_NEW_HEADS_ENABLED: undefined }, () => { + WsTestHelper.withOverriddenEnvsInMochaTest({ WS_NEW_HEADS_ENABLED: false }, () => { it('@release should subscribe to newHeads and receive a valid JSON RPC response', async (done) => { - expect(ConfigService.get('WS_NEW_HEADS_ENABLED')).to.be.undefined; + expect(ConfigService.get('WS_NEW_HEADS_ENABLED')).to.be.false; const webSocket = new WebSocket(WS_RELAY_URL); const subscriptionId = 1; diff --git a/packages/ws-server/tests/helper/index.ts b/packages/ws-server/tests/helper/index.ts index 77d03e00e7..de5e944616 100644 --- a/packages/ws-server/tests/helper/index.ts +++ b/packages/ws-server/tests/helper/index.ts @@ -168,5 +168,5 @@ export class WsTestConstant { public static readonly FAKE_TX_HASH = `0x${'00'.repeat(20)}`; public static readonly STANDARD_WEB_SOCKET = 'Standard Web Socket'; public static readonly ETHERS_WS_PROVIDER = 'Ethers Web Socket Provider'; - public static readonly WS_RELAY_URL = ConfigService.get('WS_RELAY_URL') || `ws://127.0.0.1:8546`; + public static readonly WS_RELAY_URL = ConfigService.get('WS_RELAY_URL'); } diff --git a/packages/ws-server/tests/unit/validations.spec.ts b/packages/ws-server/tests/unit/validations.spec.ts index 7ebd6e103c..3b7942042e 100644 --- a/packages/ws-server/tests/unit/validations.spec.ts +++ b/packages/ws-server/tests/unit/validations.spec.ts @@ -68,7 +68,6 @@ describe('validations unit test', async function () { ]; INVALID_REQUESTS.forEach((request) => { - console.log(request); // @ts-ignore expect(validateJsonRpcRequest(request, logger, requestDetails)).to.be.false; }); diff --git a/tools/brownie-example/LICENSE b/tools/brownie-example/LICENSE index b902617e1b..56eb59cd28 100644 --- a/tools/brownie-example/LICENSE +++ b/tools/brownie-example/LICENSE @@ -1,7 +1,6 @@ Hedera Brownie Example Copyright (C) 2024 Hedera Hashgraph, LLC - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at