diff --git a/lib/rpc/UniJsonRpcProvider.ts b/lib/rpc/UniJsonRpcProvider.ts index 712abbdccd..4bcc0116db 100644 --- a/lib/rpc/UniJsonRpcProvider.ts +++ b/lib/rpc/UniJsonRpcProvider.ts @@ -297,10 +297,10 @@ export class UniJsonRpcProvider extends StaticJsonRpcProvider { case 'eth_call': // eth_estimateGas result type is number, so we can compare directly without casting to number type case 'eth_estimateGas': - if (castedProviderResponse.result !== castedProviderResponse.result) { + if (castedProviderResponse.result !== castedEvaluatedProviderResponse.result) { this.log.error( { stitchedMethodName, args }, - `Provider result mismatch: ${castedProviderResponse.result} from ${selectedProvider.providerId} vs ${castedProviderResponse.result} from ${otherProvider.providerId}` + `Provider result mismatch: ${castedProviderResponse.result} from ${selectedProvider.providerId} vs ${castedEvaluatedProviderResponse.result} from ${otherProvider.providerId}` ) selectedProvider.logRpcResponseMismatch(stitchedMethodName, otherProvider) } else if (castedProviderResponse.error?.data !== castedEvaluatedProviderResponse.error?.data) { @@ -342,6 +342,7 @@ export class UniJsonRpcProvider extends StaticJsonRpcProvider { selectedProvider.logRpcResponseMatch(stitchedMethodName, otherProvider) } } else if (castedProviderResponse.error?.data !== castedEvaluatedProviderResponse.error?.data) { + // when comparing the error, the most important part is the data field this.log.error( { stitchedMethodName, args }, `Provider error mismatch: ${JSON.stringify(castedProviderResponse.error)} from ${ diff --git a/lib/util/eth_feeHistory.ts b/lib/util/eth_feeHistory.ts index 6963d58f81..bae458ced8 100644 --- a/lib/util/eth_feeHistory.ts +++ b/lib/util/eth_feeHistory.ts @@ -1,5 +1,5 @@ export type EthFeeHistory = { - oldestBlock: number + oldestBlock: string reward: string[] baseFeePerGas: string[] gasUsedRatio: number[] diff --git a/test/mocha/unit/rpc/UniJsonRpcProvider.test.ts b/test/mocha/unit/rpc/UniJsonRpcProvider.test.ts index b641c48020..4d61316aff 100644 --- a/test/mocha/unit/rpc/UniJsonRpcProvider.test.ts +++ b/test/mocha/unit/rpc/UniJsonRpcProvider.test.ts @@ -11,6 +11,8 @@ import { import { SingleJsonRpcProvider } from '../../../../lib/rpc/SingleJsonRpcProvider' import { default as bunyan } from 'bunyan' import { ProviderHealthiness } from '../../../../lib/rpc/ProviderHealthState' +import { JsonRpcResponse } from 'hardhat/types' +import { EthFeeHistory } from '../../../../lib/util/eth_feeHistory' const UNI_PROVIDER_TEST_CONFIG: UniJsonRpcProviderConfig = { HEALTH_EVALUATION_WAIT_PERIOD_IN_S: 0, @@ -1008,14 +1010,155 @@ describe('UniJsonRpcProvider', () => { expect(spy2.callCount).to.equal(1) }) - it('Test compare RPC response for eth_blockNumber', async () => { - uniProvider = new UniJsonRpcProvider( - ChainId.MAINNET, - SINGLE_RPC_PROVIDERS[ChainId.MAINNET], - log, - UNI_PROVIDER_TEST_CONFIG, - 1.0, - 1 - ) + it('Test compare RPC result for eth_call with same results', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + uniProvider.compareRpcResponses('0x123', '0x123', selectedProvider, otherProvider, 'call', []) + + expect(spy.callCount).to.equal(1) + }) + + it('Test compare RPC result for eth_call with different results', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMismatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + uniProvider.compareRpcResponses('0x321', '0x123', selectedProvider, otherProvider, 'call', []) + + expect(spy.callCount).to.equal(1) + }) + + it('Test compare RPC result for eth_estimateGas with same results', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + const providerResult: JsonRpcResponse = { jsonrpc: '2.0', result: '0x123', id: 76 } + const otherProviderResult: JsonRpcResponse = { jsonrpc: '2.0', result: '0x123', id: 76 } + uniProvider.compareRpcResponses(providerResult, otherProviderResult, selectedProvider, otherProvider, 'send', [ + 'eth_call', + ]) + + expect(spy.callCount).to.equal(1) + }) + + it('Test compare RPC result for eth_estimateGas with different results', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMismatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + const providerResult: JsonRpcResponse = { jsonrpc: '2.0', result: '0x123', id: 76 } + const otherProviderResult: JsonRpcResponse = { jsonrpc: '2.0', result: '0x321', id: 76 } + uniProvider.compareRpcResponses(providerResult, otherProviderResult, selectedProvider, otherProvider, 'send', [ + 'eth_call', + ]) + + expect(spy.callCount).to.equal(1) + }) + + it('Test compare RPC error for eth_estimateGas with same errors', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + const providerError = { code: '123', data: '0x123', error: 'CALL_EXCEPTION' } + const otherProviderError = { code: '123', data: '0x123', error: 'CALL_EXCEPTION' } + uniProvider.compareRpcResponses(providerError, otherProviderError, selectedProvider, otherProvider, 'send', [ + 'eth_call', + ]) + + expect(spy.callCount).to.equal(1) + }) + + it('Test compare RPC error for eth_estimateGas with different errors', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + const providerError = { code: '123', data: '0x321', error: 'CALL_EXCEPTION' } + const otherProviderError = { code: '123', data: '0x123', error: 'CALL_EXCEPTION' } + uniProvider.compareRpcResponses(providerError, otherProviderError, selectedProvider, otherProvider, 'send', [ + 'eth_call', + ]) + + expect(spy.callCount).to.equal(1) + }) + + it('Test compare RPC result for eth_feeHistory with different results, but one is a number and the other is a string', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + const ethFeeHistory: EthFeeHistory = { + oldestBlock: '0x1347665', + reward: ['0x21f43815'], + baseFeePerGas: ['0x7750ad57'], + gasUsedRatio: [0.4496709], + baseFeePerBlobGas: ['0x1'], + blobGasUsedRatio: [0.4496709], + } + const providerResult: JsonRpcResponse = { jsonrpc: '2.0', result: ethFeeHistory, id: 76 } + const otherProviderResult: JsonRpcResponse = { jsonrpc: '2.0', result: ethFeeHistory, id: 76 } + uniProvider.compareRpcResponses(providerResult, otherProviderResult, selectedProvider, otherProvider, 'send', [ + 'eth_feeHistory', + ]) + + expect(spy.callCount).to.equal(1) + }) + + it('Test compare RPC result for eth_feeHistory with different results', async () => { + const rpcProviders = createNewSingleJsonRpcProviders() + const selectedProvider = rpcProviders[0] + const otherProvider = rpcProviders[1] + const spy = sandbox.spy(selectedProvider, 'logRpcResponseMismatch') + + uniProvider = new UniJsonRpcProvider(ChainId.MAINNET, rpcProviders, log, UNI_PROVIDER_TEST_CONFIG, 1.0, 1) + + const ethFeeHistory: EthFeeHistory = { + oldestBlock: '0x1347665', + reward: ['0x21f43815'], + baseFeePerGas: ['0x7750ad57'], + gasUsedRatio: [0.4496709], + baseFeePerBlobGas: ['0x1'], + blobGasUsedRatio: [0.4496709], + } + const ethFeeHistory2: EthFeeHistory = { + oldestBlock: '0x1347661', + reward: ['0x21f43815'], + baseFeePerGas: ['0x7750ad57'], + gasUsedRatio: [0.4496709], + baseFeePerBlobGas: ['0x1'], + blobGasUsedRatio: [0.4496709], + } + const providerResult: JsonRpcResponse = { jsonrpc: '2.0', result: ethFeeHistory, id: 76 } + const otherProviderResult: JsonRpcResponse = { jsonrpc: '2.0', result: ethFeeHistory2, id: 76 } + uniProvider.compareRpcResponses(providerResult, otherProviderResult, selectedProvider, otherProvider, 'send', [ + 'eth_feeHistory', + ]) + + expect(spy.callCount).to.equal(1) }) })