diff --git a/packages/relay/src/lib/clients/mirrorNodeClient.ts b/packages/relay/src/lib/clients/mirrorNodeClient.ts index acb24cf76..997ba7689 100644 --- a/packages/relay/src/lib/clients/mirrorNodeClient.ts +++ b/packages/relay/src/lib/clients/mirrorNodeClient.ts @@ -18,22 +18,22 @@ * */ +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import Axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; +import axiosRetry from 'axios-retry'; +import { install as betterLookupInstall } from 'better-lookup'; +import { ethers } from 'ethers'; import http from 'http'; import https from 'https'; import { Logger } from 'pino'; -import { ethers } from 'ethers'; -import axiosRetry from 'axios-retry'; -import constants from './../constants'; import { Histogram, Registry } from 'prom-client'; + +import { formatRequestIdMessage, formatTransactionId, parseNumericEnvVar } from '../../formatters'; import { predefined } from '../errors/JsonRpcError'; +import { MirrorNodeClientError } from '../errors/MirrorNodeClientError'; import { SDKClientError } from '../errors/SDKClientError'; -import { IOpcodesResponse } from './models/IOpcodesResponse'; -import { install as betterLookupInstall } from 'better-lookup'; +import { EthImpl } from '../eth'; import { CacheService } from '../services/cacheService/cacheService'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import { MirrorNodeClientError } from '../errors/MirrorNodeClientError'; -import Axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; -import { formatRequestIdMessage, formatTransactionId, parseNumericEnvVar } from '../../formatters'; import { IContractCallRequest, IContractCallResponse, @@ -45,7 +45,8 @@ import { MirrorNodeTransactionRecord, RequestDetails, } from '../types'; -import { EthImpl } from '../eth'; +import constants from './../constants'; +import { IOpcodesResponse } from './models/IOpcodesResponse'; type REQUEST_METHODS = 'GET' | 'POST'; @@ -1364,9 +1365,15 @@ export class MirrorNodeClient { ); } + // Create a modified copy of requestDetails + const modifiedRequestDetails = { + ...requestDetails, + ipAddress: constants.MASKED_IP_ADDRESS, + }; + const transactionRecords = await this.repeatedRequest( this.getTransactionById.name, - [transactionId, requestDetails, 0], + [transactionId, modifiedRequestDetails, 0], this.MIRROR_NODE_REQUEST_RETRY_COUNT, requestDetails, ); diff --git a/packages/relay/src/lib/constants.ts b/packages/relay/src/lib/constants.ts index 8c6b9eaeb..26b0ac072 100644 --- a/packages/relay/src/lib/constants.ts +++ b/packages/relay/src/lib/constants.ts @@ -18,9 +18,8 @@ * */ -import { BigNumber } from 'bignumber.js'; - import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { BigNumber } from 'bignumber.js'; enum CACHE_KEY { ACCOUNT = 'account', @@ -210,6 +209,8 @@ export default { // computed hash of an empty Trie object DEFAULT_ROOT_HASH: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + MASKED_IP_ADDRESS: 'xxx.xxx.xxx.xxx', + // The fee is calculated via the fee calculator: https://docs.hedera.com/hedera/networks/mainnet/fees // The maximum fileAppendChunkSize is currently set to 5KB by default; therefore, the estimated fees for FileCreate below are based on a file size of 5KB. // FILE_APPEND_BASE_FEE & FILE_APPEND_RATE_PER_BYTE are calculated based on data colelction from the fee calculator: diff --git a/packages/relay/src/lib/eth.ts b/packages/relay/src/lib/eth.ts index 66c8b66b6..6116bfbc8 100644 --- a/packages/relay/src/lib/eth.ts +++ b/packages/relay/src/lib/eth.ts @@ -18,31 +18,13 @@ * */ +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { FileId, Hbar, PrecheckStatusError } from '@hashgraph/sdk'; import crypto from 'crypto'; +import { Transaction as EthersTransaction } from 'ethers'; import { Logger } from 'pino'; -import { Eth } from '../index'; -import { Utils } from '../utils'; -import constants from './constants'; -import { Precheck } from './precheck'; -import { MirrorNodeClient } from './clients'; import { Counter, Registry } from 'prom-client'; -import { IAccountInfo } from './types/mirrorNode'; -import { LogsBloomUtils } from '../logsBloomUtils'; -import { DebugService } from './services/debugService'; -import { SDKClientError } from './errors/SDKClientError'; -import { Transaction as EthersTransaction } from 'ethers'; -import HAPIService from './services/hapiService/hapiService'; -import { JsonRpcError, predefined } from './errors/JsonRpcError'; -import { Block, Log, Transaction, Transaction1559 } from './model'; -import { FileId, Hbar, PrecheckStatusError } from '@hashgraph/sdk'; -import { CacheService } from './services/cacheService/cacheService'; -import { CommonService, FilterService } from './services/ethService'; -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import { IDebugService } from './services/debugService/IDebugService'; -import { MirrorNodeClientError } from './errors/MirrorNodeClientError'; -import { IReceiptRootHash, ReceiptsRootUtils } from '../receiptsRootUtils'; -import { IFilterService } from './services/ethService/ethFilterService/IFilterService'; -import { IContractCallRequest, IContractCallResponse, IFeeHistory, ITransactionReceipt, RequestDetails } from './types'; + import { ASCIIToHex, formatContractResult, @@ -59,6 +41,25 @@ import { trimPrecedingZeros, weibarHexToTinyBarInt, } from '../formatters'; +import { Eth } from '../index'; +import { LogsBloomUtils } from '../logsBloomUtils'; +import { IReceiptRootHash, ReceiptsRootUtils } from '../receiptsRootUtils'; +import { Utils } from '../utils'; +import { MirrorNodeClient } from './clients'; +import constants from './constants'; +import { JsonRpcError, predefined } from './errors/JsonRpcError'; +import { MirrorNodeClientError } from './errors/MirrorNodeClientError'; +import { SDKClientError } from './errors/SDKClientError'; +import { Block, Log, Transaction, Transaction1559 } from './model'; +import { Precheck } from './precheck'; +import { CacheService } from './services/cacheService/cacheService'; +import { DebugService } from './services/debugService'; +import { IDebugService } from './services/debugService/IDebugService'; +import { CommonService, FilterService } from './services/ethService'; +import { IFilterService } from './services/ethService/ethFilterService/IFilterService'; +import HAPIService from './services/hapiService/hapiService'; +import { IContractCallRequest, IContractCallResponse, IFeeHistory, ITransactionReceipt, RequestDetails } from './types'; +import { IAccountInfo } from './types/mirrorNode'; const _ = require('lodash'); const createHash = require('keccak'); @@ -1720,9 +1721,16 @@ export class EthImpl implements Eth { if (submittedTransactionId) { try { const formattedTransactionId = formatTransactionIdWithoutQueryParams(submittedTransactionId); + + // Create a modified copy of requestDetails + const modifiedRequestDetails = { + ...requestDetails, + ipAddress: constants.MASKED_IP_ADDRESS, + }; + const contractResult = await this.mirrorNodeClient.repeatedRequest( this.mirrorNodeClient.getContractResult.name, - [formattedTransactionId, requestDetails], + [formattedTransactionId, modifiedRequestDetails], this.mirrorNodeClient.getMirrorNodeRequestRetryCount(), requestDetails, ); diff --git a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts index a791319e8..a5b3f1e7f 100644 --- a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts +++ b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts @@ -19,9 +19,6 @@ */ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import { expect, use } from 'chai'; -import sinon from 'sinon'; -import chaiAsPromised from 'chai-as-promised'; import { FileAppendTransaction, FileId, @@ -32,21 +29,27 @@ import { TransactionId, TransactionResponse, } from '@hashgraph/sdk'; -import { HbarLimitService } from '../../../src/lib/services/hbarLimitService'; +import MockAdapter from 'axios-mock-adapter'; +import { expect, use } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; import { EventEmitter } from 'events'; import pino from 'pino'; -import { SDKClient } from '../../../src/lib/clients'; -import { ACCOUNT_ADDRESS_1, DEFAULT_NETWORK_FEES, MAX_GAS_LIMIT_HEX, NO_TRANSACTIONS } from './eth-config'; +import { Counter } from 'prom-client'; +import sinon from 'sinon'; + import { Eth, JsonRpcError, predefined } from '../../../src'; +import { formatTransactionIdWithoutQueryParams } from '../../../src/formatters'; +import { SDKClient } from '../../../src/lib/clients'; +import constants from '../../../src/lib/constants'; +import { SDKClientError } from '../../../src/lib/errors/SDKClientError'; +import { CacheService } from '../../../src/lib/services/cacheService/cacheService'; +import HAPIService from '../../../src/lib/services/hapiService/hapiService'; +import { HbarLimitService } from '../../../src/lib/services/hbarLimitService'; +import { RequestDetails } from '../../../src/lib/types'; import RelayAssertions from '../../assertions'; import { getRequestId, mockData, overrideEnvsInMochaDescribe, signTransaction } from '../../helpers'; +import { ACCOUNT_ADDRESS_1, DEFAULT_NETWORK_FEES, MAX_GAS_LIMIT_HEX, NO_TRANSACTIONS } from './eth-config'; import { generateEthTestEnv } from './eth-helpers'; -import { SDKClientError } from '../../../src/lib/errors/SDKClientError'; -import { RequestDetails } from '../../../src/lib/types'; -import MockAdapter from 'axios-mock-adapter'; -import HAPIService from '../../../src/lib/services/hapiService/hapiService'; -import { CacheService } from '../../../src/lib/services/cacheService/cacheService'; -import { Counter } from 'prom-client'; use(chaiAsPromised); @@ -283,6 +286,34 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () }); it('should not send second transaction on error different from timeout', async function () { + restMock.onGet(contractResultEndpoint).reply(200, { hash: ethereumHash }); + const repeatedRequestSpy = sinon.spy(ethImpl['mirrorNodeClient'], 'repeatedRequest'); + sdkClientStub.submitEthereumTransaction.resolves({ + txResponse: { + transactionId: TransactionId.fromString(transactionIdServicesFormat), + } as unknown as TransactionResponse, + fileId: null, + }); + + const signed = await signTransaction(transaction); + + const resultingHash = await ethImpl.sendRawTransaction(signed, requestDetails); + const mirrorNodeRetry = 10; + const newRequestDetails = { ...requestDetails, ipAddress: constants.MASKED_IP_ADDRESS }; + const formattedTransactionId = formatTransactionIdWithoutQueryParams(transactionIdServicesFormat); + + expect(resultingHash).to.equal(ethereumHash); + sinon.assert.calledOnce(sdkClientStub.submitEthereumTransaction); + sinon.assert.calledOnceWithExactly( + repeatedRequestSpy, + 'getContractResult', + [formattedTransactionId, newRequestDetails], + mirrorNodeRetry, + requestDetails, + ); + }); + + it('should call repeated request passing masked IP address', async function () { sdkClientStub.submitEthereumTransaction .onCall(0) .throws(new SDKClientError({ status: 50 }, 'wrong transaction body'));