From 91c2a2def383d510019e29f1398628580acf54bf Mon Sep 17 00:00:00 2001 From: Eric Badiere Date: Mon, 7 Oct 2024 12:58:52 -0600 Subject: [PATCH] feat: enabled configurable server host for the Relay server (#3073) (#3074) * feat: enabled configurable server host for the Relay server (#3073) Signed-off-by: Logan Nguyen Signed-off-by: ebadiere * fix: reverted to relayServer before cherry pick Signed-off-by: Logan Nguyen --------- Signed-off-by: Logan Nguyen Signed-off-by: ebadiere Co-authored-by: Logan Nguyen --- docs/configuration.md | 72 ++++++++++--------- packages/relay/src/lib/constants.ts | 1 + packages/server/src/index.ts | 2 +- .../server/tests/acceptance/index.spec.ts | 2 + .../tests/acceptance/serverConfig.spec.ts | 2 +- .../server/tests/integration/server.spec.ts | 29 ++++++++ packages/ws-server/src/index.ts | 5 +- 7 files changed, 74 insertions(+), 39 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 8661f1c9eb..547e58e3ae 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -24,23 +24,24 @@ These properties are noted below and should be custom set per deployment. 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. | -| `HBAR_RATE_LIMIT_DURATION` | "80000" | hbar budget limit duration. This creates a timestamp, which resets all limits, when it's reached. Default is to 80000 (80 seconds). | -| `HBAR_RATE_LIMIT_TINYBAR` | "11_000_000_000" | total hbar budget in tinybars (110 hbars). | -| `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 | -| `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_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) | +| 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. | +| `HBAR_RATE_LIMIT_DURATION` | "80000" | hbar budget limit duration. This creates a timestamp, which resets all limits, when it's reached. Default is to 80000 (80 seconds). | +| `HBAR_RATE_LIMIT_TINYBAR` | "11_000_000_000" | total hbar budget in tinybars (110 hbars). | +| `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 | +| `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 @@ -71,7 +72,7 @@ Unless you need to set a non-default value, it is recommended to only populate o | `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. | +| `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_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) | @@ -108,23 +109,24 @@ Unless you need to set a non-default value, it is recommended to only populate o The following table lists the available properties along with their default values for the [Ws-server package](/packages/ws-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 | -| ------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `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_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 | -| `WS_CONNECTION_LIMIT_PER_IP` | "10" | Maximum amount of connections from a single IP address | -| `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_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. | +| 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 | +| `WS_CONNECTION_LIMIT_PER_IP` | "10" | Maximum amount of connections from a single IP address | +| `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_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. | ## Sample for connecting to Hedera Environments diff --git a/packages/relay/src/lib/constants.ts b/packages/relay/src/lib/constants.ts index 95f0d9f4a2..d43fa286df 100644 --- a/packages/relay/src/lib/constants.ts +++ b/packages/relay/src/lib/constants.ts @@ -143,6 +143,7 @@ export default { WEB_SOCKET_HTTP_PORT: process.env.WEB_SOCKET_HTTP_PORT || 8547, RELAY_PORT: process.env.SERVER_PORT || 7546, + RELAY_HOST: process.env.SERVER_HOST || 'localhost', FUNCTION_SELECTOR_CHAR_LENGTH: 10, MIRROR_NODE_RETRY_DELAY_DEFAULT: 2000, diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index dd93cc2d06..55a18cc8be 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -22,7 +22,7 @@ import app from './server'; import { setServerTimeout } from './koaJsonRpc/lib/utils'; // Import the 'setServerTimeout' function from the correct location async function main() { - const server = await app.listen({ port: process.env.SERVER_PORT || 7546 }); + const server = app.listen({ port: process.env.SERVER_PORT || 7546, host: process.env.SERVER_HOST }); // set request timeout to ensure sockets are closed after specified time of inactivity setServerTimeout(server); diff --git a/packages/server/tests/acceptance/index.spec.ts b/packages/server/tests/acceptance/index.spec.ts index 51984031a6..60c844d4ee 100644 --- a/packages/server/tests/acceptance/index.spec.ts +++ b/packages/server/tests/acceptance/index.spec.ts @@ -209,7 +209,9 @@ describe('RPC Server Acceptance Tests', function () { // start local relay, relay instance in local should not be running logger.info(`Start relay on port ${constants.RELAY_PORT}`); + logger.info(`Start relay on host ${constants.RELAY_HOST}`); relayServer = app.listen({ port: constants.RELAY_PORT }); + setServerTimeout(relayServer); if (process.env.TEST_WS_SERVER === 'true') { diff --git a/packages/server/tests/acceptance/serverConfig.spec.ts b/packages/server/tests/acceptance/serverConfig.spec.ts index e46d2e0ae1..4615705962 100644 --- a/packages/server/tests/acceptance/serverConfig.spec.ts +++ b/packages/server/tests/acceptance/serverConfig.spec.ts @@ -24,7 +24,7 @@ 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(process.env.SERVER_REQUEST_TIMEOUT_MS || '3000'); - const host = 'localhost'; + const host = process.env.SERVER_HOST || 'localhost'; const port = parseInt(process.env.SERVER_PORT || '7546'); const method = 'eth_blockNumber'; const params: any[] = []; diff --git a/packages/server/tests/integration/server.spec.ts b/packages/server/tests/integration/server.spec.ts index aecb5235dc..aefa0ebad1 100644 --- a/packages/server/tests/integration/server.spec.ts +++ b/packages/server/tests/integration/server.spec.ts @@ -63,6 +63,35 @@ describe('RPC Server', function () { this.timeout(5000); + it('should verify that the server is running with the correct host and port', async function () { + const CUSTOMIZE_PORT = '7545'; + const CUSTOMIZE_HOST = '127.0.0.1'; + const configuredServer = app.listen({ port: CUSTOMIZE_PORT, host: CUSTOMIZE_HOST }); + + return new Promise((resolve, reject) => { + configuredServer.on('listening', () => { + const address = configuredServer.address(); + + try { + expect(address).to.not.be.null; + if (address && typeof address === 'object') { + expect(address.address).to.equal(CUSTOMIZE_HOST); + expect(address.port.toString()).to.equal(CUSTOMIZE_PORT); + } else { + throw new Error('Server address is not an object'); + } + configuredServer.close(() => resolve()); + } catch (error) { + configuredServer.close(() => reject(error)); + } + }); + + configuredServer.on('error', (error) => { + reject(error); + }); + }); + }); + it('should execute "eth_chainId"', async function () { const res = await testClient.post('/', { id: '2', diff --git a/packages/ws-server/src/index.ts b/packages/ws-server/src/index.ts index 6f5e70ab73..b4566e9692 100644 --- a/packages/ws-server/src/index.ts +++ b/packages/ws-server/src/index.ts @@ -22,8 +22,9 @@ import { app, httpApp } from './webSocketServer'; import constants from '@hashgraph/json-rpc-relay/dist/lib/constants'; async function main() { - app.listen({ port: constants.WEB_SOCKET_PORT }); - httpApp.listen({ port: constants.WEB_SOCKET_HTTP_PORT }); + const host = process.env.SERVER_HOST; + app.listen({ port: constants.WEB_SOCKET_PORT, host }); + httpApp.listen({ port: constants.WEB_SOCKET_HTTP_PORT, host }); } (async () => {