1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-12 04:37:13 +01:00
metamask-extension/app/scripts/controllers/network/createInfuraClient.test.js
Elliot Winkler d7a812f42f
Add remaining tests for createInfuraClient (#15717)
Add tests for the `block-tracker-inspector` middleware — which makes
sure that the block tracker never has a reference to the latest block
which is less than a block number that shows up in an RPC method's
response — and the Infura middleware — which takes care of sending the
request to Infura, and will retry the request up to 5 times if Infura
sends back a certain type of error.

Note that the `retry-on-empty` middleware is not tested because it
currently has a [bug][1] which is making it ineffective.

[1]: https://github.com/MetaMask/eth-json-rpc-middleware/issues/139
2022-09-29 10:39:35 -06:00

390 lines
12 KiB
JavaScript

/**
* @jest-environment node
*/
import {
withMockedInfuraCommunications,
withInfuraClient,
} from './provider-api-tests/helpers';
import {
testsForRpcMethodNotHandledByMiddleware,
testsForRpcMethodAssumingNoBlockParam,
testsForRpcMethodsThatCheckForBlockHashInResponse,
testsForRpcMethodSupportingBlockParam,
} from './provider-api-tests/shared-tests';
describe('createInfuraClient', () => {
// Infura documentation: <https://docs.infura.io/infura/networks/ethereum/json-rpc-methods>
// Ethereum JSON-RPC spec: <https://ethereum.github.io/execution-apis/api-documentation/>
describe('RPC methods supported by Infura and listed in the JSON-RPC spec', () => {
describe('eth_accounts', () => {
testsForRpcMethodNotHandledByMiddleware('eth_accounts', {
numberOfParameters: 0,
});
});
describe('eth_blockNumber', () => {
testsForRpcMethodAssumingNoBlockParam('eth_blockNumber');
});
describe('eth_call', () => {
testsForRpcMethodSupportingBlockParam('eth_call', {
blockParamIndex: 1,
});
});
describe('eth_chainId', () => {
it('does not hit Infura, instead returning the chain id that maps to the Infura network, as a hex string', async () => {
const chainId = await withInfuraClient(
{ network: 'goerli' },
({ makeRpcCall }) => {
return makeRpcCall({
method: 'eth_chainId',
});
},
);
expect(chainId).toStrictEqual('0x5');
});
});
describe('eth_coinbase', () => {
testsForRpcMethodNotHandledByMiddleware('eth_coinbase', {
numberOfParameters: 0,
});
});
describe('eth_estimateGas', () => {
testsForRpcMethodAssumingNoBlockParam('eth_estimateGas');
});
describe('eth_feeHistory', () => {
testsForRpcMethodNotHandledByMiddleware('eth_feeHistory', {
numberOfParameters: 3,
});
});
describe('eth_getBalance', () => {
testsForRpcMethodSupportingBlockParam('eth_getBalance', {
blockParamIndex: 1,
});
});
describe('eth_gasPrice', () => {
testsForRpcMethodAssumingNoBlockParam('eth_gasPrice');
});
describe('eth_getBlockByHash', () => {
testsForRpcMethodAssumingNoBlockParam('eth_getBlockByHash');
});
describe('eth_getBlockByNumber', () => {
testsForRpcMethodSupportingBlockParam('eth_getBlockByNumber', {
blockParamIndex: 0,
});
});
describe('eth_getBlockTransactionCountByHash', () => {
testsForRpcMethodAssumingNoBlockParam(
'eth_getBlockTransactionCountByHash',
);
});
describe('eth_getBlockTransactionCountByNumber', () => {
// NOTE: eth_getBlockTransactionCountByNumber does take a block param at
// the 0th index, but this is not handled by our cache middleware
// currently
testsForRpcMethodAssumingNoBlockParam(
'eth_getBlockTransactionCountByNumber',
);
});
describe('eth_getCode', () => {
testsForRpcMethodSupportingBlockParam('eth_getCode', {
blockParamIndex: 1,
});
});
describe('eth_getFilterChanges', () => {
testsForRpcMethodNotHandledByMiddleware('eth_getFilterChanges', {
numberOfParameters: 1,
});
});
describe('eth_getFilterLogs', () => {
testsForRpcMethodAssumingNoBlockParam('eth_getFilterLogs');
});
describe('eth_getLogs', () => {
testsForRpcMethodNotHandledByMiddleware('eth_getLogs', {
numberOfParameters: 1,
});
});
describe('eth_getStorageAt', () => {
testsForRpcMethodSupportingBlockParam('eth_getStorageAt', {
blockParamIndex: 2,
});
});
describe('eth_getTransactionByBlockHashAndIndex', () => {
testsForRpcMethodAssumingNoBlockParam(
'eth_getTransactionByBlockHashAndIndex',
);
});
describe('eth_getTransactionByBlockNumberAndIndex', () => {
// NOTE: eth_getTransactionByBlockNumberAndIndex does take a block param
// at the 0th index, but this is not handled by our cache middleware
// currently
testsForRpcMethodAssumingNoBlockParam(
'eth_getTransactionByBlockNumberAndIndex',
);
});
describe('eth_getTransactionByHash', () => {
const method = 'eth_getTransactionByHash';
testsForRpcMethodsThatCheckForBlockHashInResponse(method);
it("refreshes the block tracker's current block if it is less than the block number that comes back in the response", async () => {
await withMockedInfuraCommunications(async (comms) => {
const request = { method };
// The first time a block-cacheable request is made, the latest
// block number is retrieved through the block tracker first.
comms.mockNextBlockTrackerRequest({ blockNumber: '0x100' });
// This is our request.
comms.mockInfuraRpcCall({
request,
response: {
result: {
blockNumber: '0x200',
},
},
});
// The block-tracker-inspector middleware will request the latest
// block through the block tracker again.
comms.mockNextBlockTrackerRequest({ blockNumber: '0x300' });
await withInfuraClient(async ({ makeRpcCall, blockTracker }) => {
await makeRpcCall(request);
expect(blockTracker.getCurrentBlock()).toStrictEqual('0x300');
});
});
});
});
describe('eth_getTransactionCount', () => {
testsForRpcMethodSupportingBlockParam('eth_getTransactionCount', {
blockParamIndex: 1,
});
});
describe('eth_getTransactionReceipt', () => {
const method = 'eth_getTransactionReceipt';
testsForRpcMethodsThatCheckForBlockHashInResponse(method);
it("refreshes the block tracker's current block if it is less than the block number that comes back in the response", async () => {
await withMockedInfuraCommunications(async (comms) => {
const request = { method };
// The first time a block-cacheable request is made, the latest
// block number is retrieved through the block tracker first.
comms.mockNextBlockTrackerRequest({ blockNumber: '0x100' });
// This is our request.
comms.mockInfuraRpcCall({
request,
response: {
result: {
blockNumber: '0x200',
},
},
});
// The block-tracker-inspector middleware will request the latest
// block through the block tracker again.
comms.mockNextBlockTrackerRequest({ blockNumber: '0x300' });
await withInfuraClient(async ({ makeRpcCall, blockTracker }) => {
await makeRpcCall(request);
expect(blockTracker.getCurrentBlock()).toStrictEqual('0x300');
});
});
});
});
describe('eth_getUncleByBlockHashAndIndex', () => {
testsForRpcMethodAssumingNoBlockParam('eth_getUncleByBlockHashAndIndex');
});
describe('eth_getUncleByBlockNumberAndIndex', () => {
// NOTE: eth_getUncleByBlockNumberAndIndex does take a block param at the
// 0th index, but this is not handled by our cache middleware currently
testsForRpcMethodAssumingNoBlockParam(
'eth_getUncleByBlockNumberAndIndex',
);
});
describe('eth_getUncleCountByBlockHash', () => {
testsForRpcMethodAssumingNoBlockParam('eth_getUncleCountByBlockHash');
});
describe('eth_getUncleCountByBlockNumber', () => {
// NOTE: eth_getUncleCountByBlockNumber does take a block param at the 0th
// index, but this is not handled by our cache middleware currently
testsForRpcMethodAssumingNoBlockParam('eth_getUncleCountByBlockNumber');
});
describe('eth_getWork', () => {
testsForRpcMethodNotHandledByMiddleware('eth_getWork', {
numberOfParameters: 0,
});
});
describe('eth_hashrate', () => {
testsForRpcMethodNotHandledByMiddleware('eth_hashrate', {
numberOfParameters: 0,
});
});
describe('eth_mining', () => {
testsForRpcMethodNotHandledByMiddleware('eth_mining', {
numberOfParameters: 0,
});
});
describe('eth_newBlockFilter', () => {
testsForRpcMethodNotHandledByMiddleware('eth_newBlockFilter', {
numberOfParameters: 0,
});
});
describe('eth_newFilter', () => {
testsForRpcMethodNotHandledByMiddleware('eth_newFilter', {
numberOfParameters: 1,
});
});
describe('eth_newPendingTransactionFilter', () => {
testsForRpcMethodNotHandledByMiddleware(
'eth_newPendingTransactionFilter',
{ numberOfParameters: 0 },
);
});
describe('eth_protocolVersion', () => {
testsForRpcMethodAssumingNoBlockParam('eth_protocolVersion');
});
describe('eth_sendRawTransaction', () => {
testsForRpcMethodNotHandledByMiddleware('eth_sendRawTransaction', {
numberOfParameters: 1,
});
});
describe('eth_sendTransaction', () => {
testsForRpcMethodNotHandledByMiddleware('eth_sendTransaction', {
numberOfParameters: 1,
});
});
describe('eth_sign', () => {
testsForRpcMethodNotHandledByMiddleware('eth_sign', {
numberOfParameters: 2,
});
});
describe('eth_submitWork', () => {
testsForRpcMethodNotHandledByMiddleware('eth_submitWork', {
numberOfParameters: 3,
});
});
describe('eth_syncing', () => {
testsForRpcMethodNotHandledByMiddleware('eth_syncing', {
numberOfParameters: 0,
});
});
describe('eth_uninstallFilter', () => {
testsForRpcMethodNotHandledByMiddleware('eth_uninstallFilter', {
numberOfParameters: 1,
});
});
});
describe('RPC methods supported by Infura but not listed in the JSON-RPC spec', () => {
describe('eth_subscribe', () => {
testsForRpcMethodNotHandledByMiddleware('eth_subscribe', {
numberOfParameters: 1,
});
});
describe('eth_unsubscribe', () => {
testsForRpcMethodNotHandledByMiddleware('eth_unsubscribe', {
numberOfParameters: 1,
});
});
describe('net_listening', () => {
testsForRpcMethodNotHandledByMiddleware('net_listening', {
numberOfParameters: 0,
});
});
describe('net_peerCount', () => {
testsForRpcMethodNotHandledByMiddleware('net_peerCount', {
numberOfParameters: 0,
});
});
describe('net_version', () => {
it('does not hit Infura, instead returning the chain id that maps to the Infura network, as a decimal string', async () => {
const chainId = await withInfuraClient(
{ network: 'goerli' },
({ makeRpcCall }) => {
return makeRpcCall({
method: 'net_version',
});
},
);
expect(chainId).toStrictEqual('5');
});
});
describe('parity_nextNonce', () => {
testsForRpcMethodNotHandledByMiddleware('parity_nextNonce', {
numberOfParameters: 1,
});
});
describe('web3_clientVersion', () => {
testsForRpcMethodAssumingNoBlockParam('web3_clientVersion');
});
});
// NOTE: The following methods are omitted because although they are listed in
// the Ethereum spec, they do not seem to be supported by Infura:
//
// - debug_getBadBlocks
// - debug_getRawBlock
// - debug_getRawHeader
// - debug_getRawReceipts
// - eth_createAccessList
// - eth_compileLLL
// - eth_compileSerpent
// - eth_compileSolidity
// - eth_getCompilers
// - eth_getProof
// - eth_maxPriorityFeePerGas
// - eth_submitHashrate
// - web3_sha3
testsForRpcMethodNotHandledByMiddleware('custom_rpc_method', {
numberOfParameters: 1,
});
});